I have a program that sets up an image to record measurements through user input using the mouse. After showing the image with imshow(), I ask the user if they would like to crop. While waiting for input to the command window, the namedWindow is not responding, and if the user clicks the window before specifying whether or not to crop, the window takes that as the first point to use for cropping.
Is there a way have the command window and namedWindow work in unison?
Constructor for measurment class:
MeasurementClass::MeasurmentClass(){
SetWorkingDirectory();
std::cout << "Before continuing, make sure image files are located in:\n\n "
<< "\"" + WorkingDirectory + "\"\n"
<< std::endl;
setfilename:
SetFileName(); //uncomment after debug
SetDate();
Image = cv::imread(XrayFileName, CV_LOAD_IMAGE_COLOR);
FinalImage = Image.clone();
if(Image.empty()){
std::cout << "Image failed to Load. Ensure correct image name and file location.\n"
<< std::endl;
goto setfilename;
}
GetDesktopResolution();
ResizeImageForDisplay();
FinalDisplayImage = DisplayImage.clone();
cv::namedWindow(WindowName, cv::WINDOW_AUTOSIZE);
cv::imshow(WindowName, DisplayImage);
cv::waitKey(10);
PromptForCrop();
}
PromptFor Crop()
void MeasurementClass::PromptForCrop(void){
std::cout << "Would you like to crop image? (y/n): ";
std::string strCrop;
std::getline(std::cin, strCrop);
std::cout << std::endl;
char Crop = strCrop[0];
switch(Crop){
case 'y':
case '\0':
CropImage();
default:
break;
}
}
Bonus
It has recently been brought to my attention that goto statements are terrible practice. In this situation, what is a good alternative to the goto statement.
You can use the cv::waitKey() return value to get user input. In order to do so, please give the image the window focus, not the command window otherwise it will not capture your key:
char c = 'q';
cv::Mat image = cv::imread( "C:/local/opencv30/sources/samples/data/lena.jpg" );
cv::imshow( "image", image );
do
{
c = cv::waitKey();
}
while ( c != 'y' && c != 'n' );
if ( c == 'y' )
cout << "yes" << endl;
else if ( c == 'n' )
cout << "no" << endl;
Related
I'm trying to get cv::VideoWriter to work but I'm having trouble.
if (recording)
{
vid.write(imagecl);
std::cout << "\trecording..." << std::endl;
}
cv::imshow(CAMERA_TOPIC, imagecl);
rec_key = cv::waitKey(1);
imagecl.release();
if (rec_key == 114 && !recording)
{
std::cout << "\t\tStarted Recording" << std::endl;
auto now = std::chrono::system_clock::now();
now_time = std::chrono::system_clock::to_time_t(now);
vidname = VIDEO_PATH + date_str(std::ctime(&now_time)) + ".mp4";
std::cout << "\tSaving video to -> " << vidname << std::endl;
codec = cv::VideoWriter::fourcc('a','v','c','1');
vid = cv::VideoWriter(vidname, codec, 30, cv::Size(frame_width, frame_height), true);
recording = true;
}
else if (rec_key == 115 && recording)
{
std::cout << "\t\tEnded recording" << std::endl;
vid.release();
recording = false;
}
This code is part of a video_recorder function what is executing inside an infinite loop. I'm using another thread to fill the imagecl with the frames I want to record. The cv::imshow is working properly (it opens a window and displays the frames), but I can't get to save videos with cv::VideoWriter. The 'r' and 's' keys are triggering the conditions as I get the terminal messages of "started recording" and then "recording" each loop and then "ended recording". I double checked the path and it is correct. I'm saving to "/home/username/videoname.mp4". What am I doing wrong?
I have a simple OpenCV application that takes a video stream from the webcam, and when the spacebar is pressed it captures the current image and freezes on that image. When I try to use the cv::imwrite() method to save the picture to disk, it does not work. The code successfully compiles but it does not save the image. It is returning a false value as well from the call. I am not sure if this is an issue of type of image or something else, but I seem to be stumped.
Here is the code for my current cpp class:
#include <iostream>
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
using namespace std;
using namespace cv;
Mat picture;
char key;
class FacialRec {
};
int main() {
//Starting the video
VideoCapture videoCapture(0);
if (!videoCapture.isOpened()) {
cout << "Unable to open video file." << endl;
return 1;
}
namedWindow("Webcam", CV_WINDOW_AUTOSIZE);
while(true) {
Mat frame;
videoCapture.retrieve(frame);
bool success = videoCapture.read(frame);
if (!success) {
cout << "Could not read from video file" << endl;
return 1;
}
imshow("Webcam", frame);
key = waitKey(30);
if (key == 27) { //escape key pressed: stop program
cout << "ESC pressed. Program closing..." << endl;
break;
}else if (key == ' ') { //spacebar pressed: take a picture
picture = frame;
key = -1;
while (true) {
imshow("Webcam", picture);
key = waitKey(30);
if (key == 27 || key == 32) {
cout << "ESC or SPACE pressed. Returning to video..." << endl;
break;
}
if (key == 115) {
//trying to save to current directory
bool maybe = imwrite("/testimage.jpg", picture);
// maybe bool is always getting value of 0, or false
cout << "s was pressed. saving image " << maybe << endl;
}
}
}
}
return 0;
}
You are attempting to write testimage.jpg to the / directory. The executing program probably doesn't have sufficient permissions to write to that directory. Based on your comment, you probably want
//trying to save to current directory
bool maybe = imwrite("./testimage.jpg", picture);
Since . denotes the current working directory.
OpenCV sometimes has problems to write to a .jpg image. Try to change that to .png or .bmp to see if that makes a difference in your case.
If you have further issues with writing images, you can debug them in OpenCV by adding this few lines of code to display them and see if they are valid:
// Create a window for display.
namedWindow( "Display window", WINDOW_AUTOSIZE );
// Show our image inside it.
imshow( "Display window", picture );
// Wait for a keystroke in the window
waitKey(0);
A few suggestions.
try a different file format.
does your IDE defiantly know your target folder / home path directory?
Is your image definitely valid? does it show when you imshow()?
I'm writing an live video processing program in c++, and want to be able to toggle three windows with the same mjpeg stream, in color, grayscale, and monochrome. I have all the image feeds running, but, since my screen is small, I want to be able to toggle them on and off individually. To do this, I have written the code below, but calling destroyWindow("[windowname]"); stops the whole program, instead. I've already read the documentation, and putting void in front of it doesn't help. Can anybody tell me what I'm doing wrong?
Here's the code (it's in an infinite loop, until the break you see below is called):
imshow("Color", imageColor);
imshow("Monochrome", imageMonochrome);
imshow("Grayscale", imageGrayscale);
int keyPressed = waitKey(0);
if (keyPressed > 0)
{
cout << keyPressed;
cout << "key was pressed\n";
// Press C to toggle color window
if (99 == keyPressed)
{
if (colorOpen)
{
cout << "Color window closed\n";
void destroyWindow("Color");
colorOpen = false;
}
if (!colorOpen)
{
cout << "Color window opened\n";
imshow("Color", imageColor);
colorOpen = true;
}
}
// Press M to toggle monochrome window
if (109 == keyPressed)
{
if (monochromeOpen)
{
cout << "Monochrome window closed\n";
void destroyWindow("Monochrome");
monochromeOpen = false;
}
if (!monochromeOpen)
{
cout << "Monochrome window opened\n";
imshow("Monochrome", imagebw);
monochromeOpen = true;
}
}
// Press G to toggle grayscale window
if (103 == keyPressed)
{
if (grayscaleOpen)
{
cout << "Grayscale window closed\n";
void destroyWindow("Grayscale");
grayscaleOpen = false;
}
if (!grayscaleOpen)
{
cout << "Grayscale window opened\n";
imshow("Grayscale", image);
grayscaleOpen = true;
}
}
// Break out of infinite loop when [ESC] is pressed:
if (27 == keyPressed)
{
cout << "Escape Pressed\n";
break;
}
}
The code you pasted terminates after calling destroyWindow (by running off the end of main). If that's not what you want to happen, write code that does something else after calling destroyWindow. Perhaps you want a loop?
I have written the following code below to display a video in OpenCV. I have compiled it fine but when I run it, the window that is supposed to show the video opens but it is too small to actually see if the video is playing. Everything else seems to be working fine. The width, height and number of frames are printed on the command line as coded. Anyone know what the problem is? Check it out.
void info()
{
cout << "This program will accept input video with fixed lengths and produce video textures" << endl;
}
int main(int argc, char *argv[])
{
info();
if(argc != 2)
{
cout << "Please enter more parameters" << endl;
return -1;
}
const string source = argv[1];
VideoCapture input_vid(source);
if(! input_vid.isOpened())
{
cout << "Error: Could not find input video file" << source << endl;
return -1;
}
Size S = Size((int) input_vid.get(CV_CAP_PROP_FRAME_WIDTH), //Acquire size of input video
(int) input_vid.get(CV_CAP_PROP_FRAME_HEIGHT));
cout << "Width: = " << S.width << " Height: = " << S.height << " Number of frames: " << input_vid.get(CV_CAP_PROP_FRAME_COUNT)<<endl;
const char* PLAY = "Video player";
namedWindow(PLAY, CV_WINDOW_AUTOSIZE);
//imshow(PLAY,100);
char c;
c = (char)cvWaitKey(27);
//if ( c == 27)break;
return 0;
}
assuming video is from webcam:
capture = CaptureFromCAM( 0 );
SetCaptureProperty(capture,CV_CAP_PROP_FRAME_HEIGHT, 640);
SetCaptureProperty(capture,CV_CAP_PROP_FRAME_WIDTH, 480);
this will fix your problem
another simple tweak could be using CV_WINDOW_NORMAL instead of CV_WINDOW_AUTOSIZE
namedWindow(PLAY, CV_WINDOW_AUTOSIZE);
which lets you resize the window manually
I have a Tcl procedure which magnifies an image.
proc ShowWindow {wtitle zfactor imgdata} {
puts stdout "Now in the Tcl procedure ShowWindow!";
image create photo idata -data $imgdata; # create a photo image from the input data
image create photo the_window; # final window
the_window copy idata -zoom $zfactor $zfactor; # copy the original and magnify
wm title . $wtitle; # window title
wm resizable . false false; # no resizing in both x and y directions
catch {destroy .dwindow}; # since this procedure will be called multiple times
# we need to suppress the 'window name "dwindow" already exists in parent' message
label .dwindow -image the_window; # create a label to display the image
pack .dwindow; # display the image
}
I would like to call this Tcl procedure from C++.
I think that "imgdata" is a ByteArray. Is this correct?
The pertinent code fragment is shown below:
// ...Tcl/Tk initialization omitted...
unsigned char *img; // PPM image data
int num_bytes; // PPM image file size
// ...routines to initialize img and num_bytes omitted...
Tcl_Obj *tcl_raw;
// transfer the PPM image data into Tcl_Obj
if (!(tcl_raw = Tcl_NewByteArrayObj(img, num_bytes))) {
cerr << "Tcl_NewByteArrayObj() failed!" << endl;
cerr << "Exiting..." << endl;
return 1;
} else {
cerr << "Tcl_NewByteArrayObj() succeeded!" << endl;
}
Tcl_IncrRefCount(tcl_raw); // is this really necessary?
// set the Tcl variable "imgdata" to the Tcl_Obj
if (Tcl_SetVar2Ex(tcl_interpreter, "imgdata", "", tcl_raw, TCL_LEAVE_ERR_MSG) == NULL) {
cerr << "Tcl_SetVar2Ex() failed!" << endl;
cerr << "Exiting..." << endl;
return 1;
} else {
cerr << "Tcl_SetVar2Ex() succeeded!" << endl;
}
// execute the Tcl procedure
if (Tcl_Eval(tcl_interpreter, "ShowWindow TheImage 8 $imgdata") != TCL_OK) {
cerr << "Tcl_Eval() failed!" << endl;
cerr << "Tcl_GetStringResult() = " << Tcl_GetStringResult(tcl_interpreter) << endl;
cerr << "Exiting..." << endl;
return 1;
} else {
cerr << "Tcl_Eval() succeeded!" << endl;
}
The program fails at Tcl_Eval(). The program output is:
...
Tcl_NewByteArrayObj() succeeded!
Tcl_SetVar2Ex() succeeded!
Tcl_Eval() failed!
Tcl_GetStringResult() = can't read "imgdata": variable is array
Exiting...
What is the recommended way of doing this?
You can treat the Tcl ByteArrayObj type as a buffer by using Tcl_ByteArraySetLength or Tcl_GetByteArrayFromObj which both give you access to the data part of the Tcl object.
Tcl_Obj *dataObj = Tcl_NewObj();
char *dataPtr = Tcl_SetByteArrayLength(dataObj, 1024);
Now you can use dataPtr to set the bytes in the object. The Tcl_SetByteArrayLength function will make this object become a ByteArray type.
However, you might also want to look at imgscale which I use for stretching Tk images and this uses various interpolation modes eg:
image create photo thumbnail
::imgscale::bilinear $myphoto 64 64 thumbnail 1.0
to downscale some photo into a thumbnail image.