I have a VS console application that is built using opencv library. I am displaying image using the opencv imshow function. The thing is that all the imshow windows overlap over each other and it is difficult to toggle between them. How can I prevent the overlap and display them separately and toggle between them
The way to go about this programatically, is to call resizeWindow() to define each windows' size and moveWindow() to place them at specific locations in your screen.
void cv::resizeWindow(const string& winname, int width, int height)
void cv::moveWindow(const string& winname, int x, int y)
Although this is a late reply, you may find it useful to call moveWindow() after each imshow() call. A language independent solution is given here.
Example steps :-
call imshow("first image", img1)
call moveWindow("first image", img1, 0, 0) //Default position of window is at col,row == 0,0. So, this line is optional.
call imshow("second image", img2)
set firstImageWidth = width of img1
set mySpacing = 40 //vary this to increase/decrease the gap between the image windows.
call moveWindow("first image", firstImageWidth + mySpacing , 0)
Then, add these lines to prevent output windows from being forever active.
set myTime = 7000 //in milliseconds. Here, 7000 ms == 7 secs to show our image windows.
call waitKey(myTime)
call waitKey(1) //this is a trick. Otherwise, the windows are opened indefinitely.
At the moment, I am using Java SE8 with OpenCV 4.2. The above method works for me.
[Screenshot of the above example in action.][1]
[1]: https://i.stack.imgur.com/JaTI0.png
Here is a Java+OpenCV code snippet for the display part:
...
//display image. Using OpenCV HighGui class methods.
String inputWindowName = "This window shows input image";
String outputWindowName = "This window shows output image";
HighGui displayWindow = new HighGui();
displayWindow.imshow(inputWindowName, img1);
displayWindow.imshow(outputWindowName, img2);
displayWindow.moveWindow(outputWindowName, img1.cols()+40, 0);
displayWindow.waitKey(7000);
displayWindow.waitKey(1);
Related
I want to display a cv::Mat in a Gui written by gtkmm. So I have done a test.
I have a widget Gtk::Image image, and I want to set the image with the following two methods:
// first method, display from file
void displayImage1()
{
Glib::RefPtr<Gdk::Pixbuf> pixbuf = Gdk::Pixbuf::create_from_file("gtk.png");
image.set(pixbuf);
}
// second method, display from cv::Mat
void displayImage2()
{
cv::Mat outImage = cv::imread("gtk.png");
cv::cvtColor(outImage, outImage, CV_BGR2RGB);
Glib::RefPtr<Gdk::Pixbuf> pixbuf = Gdk::Pixbuf::create_from_data(outImage.data, Gdk::COLORSPACE_RGB,false, 8, outImage.cols, outImage.rows, outImage.step);
image.set(pixbuf);
}
The first method works well.
However, the second method doesn't work well, I got a destroyed image on the screen as shown in the picture.
If I set the has_alpha parameter to true, the result is also strange (see pic. below).
Similar tests were done by using Gtk::DrawingArea. Different IDEs are used (but all g++ compiler under linux). All same results.
Update:
I tested lots of images. Sometimes the images are broken, sometimes the programs crashed with
The program has unexpectedly finished.
Usually, this kind of "broken" image trigger a warning in my head: "wrong rawstride !". The rawstride in Gdk::Pixbuf in the length in bytes of a line of data. That's because you may have some byte-alignment constraints, so there may be some padding at the end of one line.
I checked what this step argument was, and yes, that's the same in OpenCV as the rawstride in Gdk::Pixbuf. Until I realized outImage.step is a cv:MatStep object, while Gdk::Pixbuf::create_from_data expects an int. I think you're supposed to use outImage.step[0] instead.
Please read https://docs.opencv.org/2.4/modules/core/doc/basic_structures.html#mat
here we go:
auto lenna = imread("Lenna.png");
Image image;
cvtColor(lenna, lenna, COLOR_BGR2RGB);
auto size = lenna.size();
auto img = Gdk::Pixbuf::create_from_data(lenna.data, Gdk::COLORSPACE_RGB, lenna.channels() == 4, 8, size.width, size.height, (int) lenna.step);
image.set(img);
This is what I did and it show good result on image showing
cvtColor(resize_image, resize_image, COLOR_BGR2RGB);
Pixbuf = Gdk::Pixbuf::create_from_data(resize_image.data, Gdk::COLORSPACE_RGB, false, 8, resize_image.cols, resize_image.rows, resize_image.step);
So I tested this (add scale_simple) with success for me:
From: http://orobotp.blogspot.com/2014/01/opencv-with-gtkmm3.html
Version: Gtkmm 3.22.2-2, OpenCV 4.4.0-dev, g++ 7.5.0
void displayImage2()
{
cv::Mat outImage;
outImage = cv::imread("gtk.png");
cv::cvtColor(outImage, outImage, cv::COLOR_RGB2BGR);
Glib::RefPtr<Gdk::Pixbuf> pixbuf = Gdk::Pixbuf::create_from_data(outImage.data, Gdk::COLORSPACE_RGB,false, 8, outImage.cols, outImage.rows, outImage.step)->scale_simple( outImage.cols, outImage.rows, Gdk::INTERP_BILINEAR );
image.set(pixbuf);
}
IMO, as already suggested by #Miki in the comments, this is just a lifetime issue.
I had the very same problem with similar code:
{
cv::Mat rgb;
cv::cvtColor(src, rgb, cv::COLOR_GRAY2RGB);
pixbuf = gdk_pixbuf_new_from_data(rgb.data,
GDK_COLORSPACE_RGB, FALSE, 8,
rgb.cols, rgb.rows, rgb.step,
NULL, NULL);
}
The above snippet simply does not work (or works intermittently) because, quoting the gdk_pixbuf_new_from_data documentation, "the data is owned by the caller of the function".
The problem is at the time the image is rendered, rgb has been destroyed. Adding a rgb.addref() just before the pixbuf assignment resolves the issue, although introducing a memory leak.
One solution would be to leverage the destroy callback to unreference the Mat object, e.g.:
static void
unref_mat(guchar *data, gpointer user_data)
{
((cv::Mat *) user_data)->release();
}
{
cv::Mat rgb;
cv::cvtColor(src, rgb, cv::COLOR_GRAY2RGB);
rgb.addref()
pixbuf = gdk_pixbuf_new_from_data(rgb.data,
GDK_COLORSPACE_RGB, FALSE, 8,
rgb.cols, rgb.rows, rgb.step,
unref_mat, &rgb);
}
try add a reference to outimage, like outimage.addref() . all my problems were related to that. the source image being de-referenced before the gdk_pixbuf_new_from_data get a chance to map it. leading to segfaults, corruption and so on. just be sure to release it later, or use the callback provided with gdk_pixbuf_new_from_data
For Gtkmm-2.4 and OpenCv 4.6 check https://onthim.blogspot.com/2015/10/using-opencv-in-gtk-applications.html and https://developer-old.gnome.org/gtkmm-tutorial/2.24/sec-draw-images.html.es
Mat frame;
frame = imread("gtk.png");
cv::cvtColor (frame, frame, COLOR_BGR2RGB);//COLOR_BGR2GRAY
Glib::RefPtr<Gdk::Pixbuf> image = Gdk::Pixbuf::create_from_data(frame.data,Gdk::COLORSPACE_RGB, false, 8, frame.cols, frame.rows, frame.step);
image->render_to_drawable(get_window(), get_style()->get_black_gc(),0, 0, 0, 0, image->get_width(), image->get_height(), // draw the whole image (from 0,0 to the full width,height) at 100,80 in the window
Gdk::RGB_DITHER_NONE, 0, 0);
I am working on a project with OpenFrameworks using ofxCV, ofxOpencv and ofxColorQuantizer. Technically, the project is analyzing live video captured via webcam and analysis's the image in real time to gather and output the most prominent color in the current frame. When generating the most prominent color I am using the pixel difference between the current frame and the previous frame to generate the what colors have updated and use the updated or moving areas of the video frame to figure out the most prominent colors.
The reason for using the pixel difference's to generate the color pallet is because I want to solve for the case of a user walks into the video frame, I want try and gather the color pallet of the person, for instance what they are wearing. For example red shirt, blue pants will be in the pallet and the white background will be excluded.
I have a strong background in Javascript and canvas but am fairly new to OpenFrameworks and C++ which is why I think I am running into a roadblock with this problem I described above.
Along with OpenFrameworks I am using ofxCV, ofxOpencv and ofxColorQuantizer as tools for this installation. I am taking a webcam image than making it a cv:Mat than using pyrdown on the webcam image twice followed by a absdiff of the mat which I am than trying to pass the mat into the ofxColorQuantizer. This is where I think I am running into problems — I don't think the ofxColorQuantizer likes the mat format of the image I am trying to use. I've tried looking for the different image format to try and convert the image to to solve this issue but I haven't been able to come to solution.
For efficiencies I am hoping to to the color difference and color prominence calculations on the smaller image (after I pyrdown' the image) and display the full image on the screen and the generated color palette is displayed at the bottom left like in the ofxColorQuantizer example.
I think there may be other ways to speed up the code but at the moment I am trying to get this portion of the app working first.
I have my main.cpp set up as follows:
#include "ofMain.h"
#include "ofApp.h"
#include "ofAppGlutWindow.h"
//========================================================================
int main( ){
ofAppGlutWindow window;
ofSetupOpenGL(&window, 1024,768, OF_WINDOW); // <-------- setup the GL context
// ofSetupOpenGL(1024,768,OF_WINDOW); // <-------- setup the GL context
// this kicks off the running of my app
// can be OF_WINDOW or OF_FULLSCREEN
// pass in width and height too:
ofRunApp(new ofApp());
}
My ofApp.h file is as follows:
#pragma once
#include "ofMain.h"
#include "ofxOpenCv.h"
#include "ofxCv.h"
#include "ofxColorQuantizer.h"
class ofApp : public ofBaseApp{
public:
void setup();
void update();
void draw();
ofVideoGrabber cam;
ofPixels previous;
ofImage diff;
void kMeansTest();
ofImage image;
ofImage img;
cv::Mat matA, matB;
ofImage diffCopy;
ofImage outputImage;
ofxCv::RunningBackground background;
ofxColorQuantizer colorQuantizer;
// a scalar is like an ofVec4f but normally used for storing color information
cv::Scalar diffMean;
};
And finally my ofApp.cpp is below:
#include "ofApp.h"
using namespace ofxCv;
using namespace cv;
//--------------------------------------------------------------
void ofApp::setup(){
ofSetVerticalSync(true);
cam.initGrabber(320, 240);
// get our colors
colorQuantizer.setNumColors(3);
// resize the window to match the image
// ofSetWindowShape(image.getWidth(), image.getHeight());
ofSetWindowShape(800, 600);
// imitate() will set up previous and diff
// so they have the same size and type as cam
imitate(previous, cam);
imitate(diff, cam);
imitate(previous, outputImage);
imitate(diff, outputImage);
}
//--------------------------------------------------------------
void ofApp::update(){
cam.update();
if(cam.isFrameNew()) {
matA = ofxCv::toCv(cam.getPixelsRef());
ofxCv::pyrDown(matA, matB);
ofxCv::pyrDown(matB, matA);
ofxCv::medianBlur(matA, 3);
ofxCv::toOf(matA, outputImage);
// take the absolute difference of prev and cam and save it inside diff
absdiff(previous, outputImage, diff);
}
}
//--------------------------------------------------------------
void ofApp::draw(){
// If the image is ready to draw, then draw it
if(outputImage.isAllocated()) {
outputImage.update();
outputImage.draw(0, 0, ofGetWidth(), ofGetHeight());
}
ofBackground(100,100,100);
ofSetColor(255);
ofImage diffCopy;
diffCopy = diff;
diffCopy.resize(diffCopy.getWidth()/2, diffCopy.getHeight()/2);
// there is some sort of bug / issue going on here...
// prevent the app from compiling
// comment out to run and see blank page
colorQuantizer.quantize(diffCopy.getPixelsRef());
ofLog() << "the number is " << outputImage.getHeight();
ofLog() << "the number is " << diffCopy.getHeight();
ofSetColor(255);
img.update();
// cam.draw(0, 0, 800, 600);
outputImage.draw(0, 0, 800, 600);
// colorQuantizer.draw(ofPoint(0, cam.getHeight()-20));
colorQuantizer.draw(ofPoint(0, 600-20));
// use the [] operator to get elements from a Scalar
float diffRed = diffMean[0];
float diffGreen = diffMean[1];
float diffBlue = diffMean[2];
ofSetColor(255, 0, 0);
ofRect(0, 0, diffRed, 10);
ofSetColor(0, 255, 0);
ofRect(0, 15, diffGreen, 10);
ofSetColor(0, 0, 255);
ofRect(0, 30, diffBlue, 10);
}
//--------------------------------------------------------------
void ofApp::kMeansTest(){
cv::Mat samples = (cv::Mat_<float>(8, 1) << 31 , 2 , 10 , 11 , 25 , 27, 2, 1);
cv::Mat labels;
// double kmeans(const Mat& samples, int clusterCount, Mat& labels,
cv::TermCriteria termcrit;
int attempts, flags;
cv::Mat centers;
double compactness = cv::kmeans(samples, 3, labels, cv::TermCriteria(), 2, cv::KMEANS_PP_CENTERS, centers);
cout<<"labels:"<<endl;
for(int i = 0; i < labels.rows; ++i)
{
cout<<labels.at<int>(0, i)<<endl;
}
cout<<"\ncenters:"<<endl;
for(int i = 0; i < centers.rows; ++i)
{
cout<<centers.at<float>(0, i)<<endl;
}
cout<<"\ncompactness: "<<compactness<<endl;
}
Apologies in advance for the state of my code — it's getting late and I'm trying to get this done.
My question is what is the image format openFrameworks is using for grabbing the webcam image, what is the image format that openCV expects and what should I use to switch back from a mat image to an ofImage and is there a way to getPixelsRef from a mat image?
The area of code that I think I have something wrong is the following logic.
I have this line of code which gets the video frame from the webcam matA = ofxCv::toCv(cam.getPixelsRef());
Than do a couple ofxCv procedures on the frame such as ofxCv::pyrDown(matA, matB); which I think changes the image format or pixel format of the frame
Than I convert the frame back to OF with ofxCv::toOf(matA, outputImage);,
Next I get the difference in the pixels between the current frame and the last frame, create a copy of the difference between the two frames. Potentially the issue lies here with the diff output image format
Which I pass the diff copy to colorQuantizer.quantize(diffCopy.getPixelsRef()); to try and generate the color palette in for the change in pixels.
It is the colorQuantizer class and function call that is giving me an error which reads thread error [ error ] ofTexture: allocate(): ofTextureData has 0 width and/or height: 0x0
with an EXC_BAD_ACCESS
And lastly, could there be an alternative cause for the exc_bad_access thread error rather than image formatting? Being new to c++ I'm just guessing and going off instinct of what I think the rood cause of my problem is.
Many thanks.
If I draw some circles "in a sequence of frames" in OpenCV by using this function:
void circle(Mat& img, Point center, int radius, const Scalar& color,
int thickness = 1, int lineType = 8, int shift = 0);
...is there any way to show these circle points in a separate window?
You can create as many windows as you like using the imshow function. The first argument of imshow is the window name, the second one is the image you are going to display on it.
So, a simple way to show these circles in a separated window is to create a brand new Mat (with the desired dimensions), draw the points on it and display it using imshow. To draw the points you may use the circle function with radius=1.
More info: docs.opencv.org
So currently I open images created with openCV with something like
cvNamedWindow( "Original Image", CV_WINDOW_AUTOSIZE );
cvShowImage( "Original Image", original );
but my images are quite large and go off the screen like shown here
I want windows to be resizable or at least the size of the users screen but with scrolling.
How to do such thing?
A simple way to scroll large image is by usage of trackbar and a Rectangular for snipping.
.
.
.
namedWindow("winImage",WINDOW_AUTOSIZE);
namedWindow("controlWin",WINDOW_AUTOSIZE);
int winH=300;
int winW=600;
if(winH>=largeImage.rows)winH=largeImage.rows-1;
if(winW>=largeImage.cols)winW=largeImage.cols-1;
int scrolHight=0;
int scrolWidth=0;
cvCreateTrackbar("Hscroll", "controlWin", &scrolHight, (largeImage.rows -winH));
cvCreateTrackbar("Wscroll", "controlWin", &scrolWidth, (largeImage.cols -winW));
while(waitKey(0)!='q'){
Mat winImage= largeImage( Rect(scrolWidth,scrolHight,winW,winH) );
imshow("winImage",winImage);
}//while
.
.
EDIT
Short answer: you can't "enable" it, you have to implement it.
OpenCV does have trackbars -- have a look at the documentation, in particular the cvCreateTrackbar function. However, even if you use them, you still have to write the code behind it (for determining the new ROI and determining what to actually show).
If this sounds a bit too daunting, then you can wrap the displayed image using some GUI framework. Here is an example that uses OpenCV with wxWidgets. Of course, you can use any other GUI framework (for example, Qt).
This might help for one step: Just use CV_WINDOW_NORMAL instead of CV_WINDOW_AUTOSIZE.
cvNamedWindow(yourWindowName, CV_WINDOW_NORMAL);
cvShowImage("Original Image", original);
As far as I know (but I've only recently started looking at OpenCV) you need to build the OpenCV library with the Qt GUI library as GUI backend.
Then you get all the cute functions.
Well, OK, there's not very much, but the little that is there is documented as Qt only.
EDIT: PS, since possibly other answer might sow confusion, I'm not talking about using Qt to implement such functionality yourself. I'm talking about the functionality available in OpenCV's HighGUI module.
Cheers & hth.,
The best thing that I can do with pure opencv is by modifying the opencv trackbar method. I'm using ROI to update the display image according to the slider value. The weakness of this method is, opencv trackbar is displayed horizontally not vertically like the normal scrollbar, so in this case it is up to you whether you want to rotate your image horizontally or not.
int slider_max, slider, displayHeight;
int displayWidth = 1900;
Mat src1; // original big image
Mat dst;
cv::Rect roi;
static void on_trackbar(int, void*)
{
roi = cv::Rect(slider, 0, displayWidth, displayHeight); //Update ROI for display
dst = src1(roi);
imshow("Result", dst);
}
int main(void)
{
src1 = imread("BigImg.jpg"); // your big image
cv::rotate(src1, src1, cv::ROTATE_90_CLOCKWISE); //I rotate my image because opencv trackbar is displayed horizontally
cv::resize(src1, src1, cv::Size(src1.cols/2, src1.rows/2)); // resize the image if it's too big to display in 1 window
if (src1.empty()) { cout << "Error loading src1 \n"; return -1; }
slider_max = src1.cols - displayWidth;
slider = 0;
displayHeight = src1.rows;
namedWindow("Result", WINDOW_AUTOSIZE); // Create Window
char TrackbarName[50];
sprintf(TrackbarName, "Pixel Pos");
createTrackbar(TrackbarName, "Result", &slider, slider_max, on_trackbar);
on_trackbar(slider, 0);
waitKey(0);
return 0;
}
For changing the trackbar's orientation then you will need to use Qt or other GUI How to change the position of the trackbar in OpenCV applications?
I am working on a school project with OpenCV. A major part of the program will be a comparison of histograms. There will be a database of histograms and new histograms will be created from a live video feed then compared to the histograms in the database. Right now I am just trying to get the histograms created correctly from the video feed. My problem is that the program crashes or slows down dramatically at random intervals. So my question is how do I prevent the program from crashing or slowing down? OpenCV has always been kind of flaky for me, so I'm not sure if it is an issue with my code or if it is just the nature of OpenCV. If it is to do with my code I think the issue might have something to do with the frame rates (a guess/gut feeling). I am useing "cvWaitKey" to "pace" the loading of frames, but the "Learning OpenCV" book has this to say about "cvWaitKey"
c = cvWaitKey(33);
if( c == 27 ) break;
Once we have displayed the frame, we then wait for 33 ms. If the user hits a key, then c
will be set to the ASCII value of that key; if not, then it will be set to –1. If the user hits
the Esc key (ASCII 27), then we will exit the read loop. Otherwise, 33 ms will pass and
we will just execute the loop again.
It is worth noting that, in this simple example, we are not explicitly controlling
the speed of the video in any intelligent way. We are relying solely on the timer in
cvWaitKey() to pace the loading of frames. In a more sophisticated application it would
be wise to read the actual frame rate from the CvCapture structure (from the AVI) and
behave accordingly!
You will see in my code below (modified from here) that I my loop waits 10ms before starting the next execution. Often times the program will run with no issues at all, but sometimes it will crash less than a minute in, or five minutes in, there really is not pattern that I can detect. Any suggestions on how this crash( or slow down) can be prevented would be welcomed. Also I should add that I am using OpenCV 1.1 (can't ever get OpenCV 2.0 to work right), I am using Visual Studio 2008, and I create an .MSI installer package everytime I modify my code, that is, I do not debug in Visual Studio. Dependencies are cv110.dll, cxcore110.dll, and highgui110.dll. My code is below:
// SLC (Histogram).cpp : Defines the entry point for the console application.
#include "stdafx.h"
#include <cxcore.h>
#include <cv.h>
#include <cvaux.h>
#include <highgui.h>
#include <stdio.h>
#include <sstream>
#include <iostream>
using namespace std;
int main(){
CvCapture* capture = cvCaptureFromCAM(0);
if(!cvQueryFrame(capture)){
cout<<"Video capture failed, please check the camera."<<endl;
}
else{
cout<<"Video camera capture successful!"<<endl;
};
CvSize sz = cvGetSize(cvQueryFrame(capture));
IplImage* image = cvCreateImage(sz, 8, 3);
IplImage* imgHistogram = 0;
IplImage* gray = 0;
CvHistogram* hist;
cvNamedWindow("Image Source",1);
cvNamedWindow("Histogram",1);
for(;;){
image = cvQueryFrame(capture);
//Size of the histogram -1D histogram
int bins = 256;
int hsize[] = {bins};
//Max and min value of the histogram
float max_value = 0, min_value = 0;
//Value and normalized value
float value;
int normalized;
//Ranges - grayscale 0 to 256
float xranges[] = {0, 256};
float* ranges[] = {xranges};
//Create an 8 bit single channel image to hold a grayscale version of the original picture
gray = cvCreateImage(cvGetSize(image), 8, 1);
cvCvtColor(image, gray, CV_BGR2GRAY);
//Planes to obtain the histogram, in this case just one
IplImage* planes[] = {gray};
//Get the histogram and some info about it
hist = cvCreateHist(1, hsize, CV_HIST_ARRAY, ranges,1);
cvCalcHist(planes, hist, 0, NULL);
cvGetMinMaxHistValue(hist, &min_value, &max_value);
printf("Minimum Histogram Value: %f, Maximum Histogram Value: %f\n", min_value, max_value);
//Create an 8 bits single channel image to hold the histogram and paint it white
imgHistogram = cvCreateImage(cvSize(bins, 50),8,3);
cvRectangle(imgHistogram, cvPoint(0,0), cvPoint(256,50), CV_RGB(255,255,255),-1);
//Draw the histogram
for(int i=0; i < bins; i++){
value = cvQueryHistValue_1D(hist, i);
normalized = cvRound(value*50/max_value);
cvLine(imgHistogram,cvPoint(i,50), cvPoint(i,50-normalized), CV_RGB(0,0,0));
}
cvFlip(image, NULL, 1);
cvShowImage("Image Source", image);
cvShowImage("Histogram", imgHistogram);
//Page 19 paragraph 3 of "Learning OpenCV" tells us why we DO NOT use "cvReleaseImage(&image)" in this section
cvReleaseImage(&imgHistogram);
cvReleaseImage(&gray);
cvReleaseHist(&hist);
char c = cvWaitKey(10);
//if ASCII key 27 (esc) is pressed then loop breaks
if(c==27) break;
}
cvReleaseImage(&image);
cvReleaseCapture(&capture);
cvDestroyAllWindows();
}
Only a few things I can see or recommend:
Considering the build, make sure you're building in Release. Also, make sure the build of OpenCV you're using was built with OpenMP enabled, it makes an enormous difference.
Try moving your allocations outside the loop. Every loop you're re-creating gray and other images, when they should be re-used.
The other thing is your style, which makes it difficult to give good recommendations easily. It's poor style to pre-declare a bunch of variables, this is C-style. Declare your variables just prior to their use, and the code will be easier to read.
Update: I found the issue, it was actually my hardware (well the driver I think). I was using a PS3 Eye because of the amazing frame rates, but for some reason OpenCV does not like the PS3 Eye all the time. Sometimes it works great and other times not so great. I have verfied this on three computers, all of which run my code good with a standard web cam but randomly lock up when the PS3 Eye is used. Still, thank you for your suggestions GMan!