I was having issues with OpenCV 2.4.8's "findContours" method. Specifically the following error:
OpenCV Error: Unsupported format or combination of formats ([Start]FindContours support only 8uC1 and 32sC1 images) in cvStartFindContours, file ..\..\..\..\opencv\modules\imgproc\src\contours.cpp, line 196
From the contents of the message it would seem that I am using an inappropriate image format, however I'm pretty sure that my code specifies an 8uC1 (8 bit 1 channel) matrix.
/* Threshold source image (src1 which is a grayscale image) */
Mat threshImg(src1.rows, src1.cols, CV_8UC1);
threshold(src1, threshImg, thresh, 255, CV_THRESH_BINARY);
/* Get contours */
Mat threshCopy = threshImg; // Copying image because findContours method edits image data
std::vector<std::vector<Point>> contours;
findContours(threshCopy, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, Point(0,0));
I am compiling the code on the command line using cl and link as follows:
$: cl NameOfCode.cpp -W2 -EHsc -c -I OpenCVIncludeDirectory
$: link NameOfCode.obj -LIBPATH:OpenCVLibraryDirectory opencv_core248.lib opencv_highgui248.lib opencv_imgproc248.lib
To enable the usage of cl and link I run vsvars32.bat from Visual studio 2010:
$: "C:\Program Files\Microsoft Visual Studio 10.0\Common7\Tools\vsvars32.bat"
I'm rewrite your code,I think it fine you can try it.
//Copy the src1 image to threshImg
Mat threshImg = src1.clone();
//Covert the threshImg from 8-channel to 1-channel and threshold it to binary image.
cvtColor(threshImg,threshImg, CV_RGB2GRAY);
threshold(src1, threshImg, thresh, 255, CV_THRESH_BINARY);
//Finnaly you can get a contours.
Mat threshCopy = threshImg.clone;
std::vector<std::vector<Point>> contours;
findContours(threshCopy, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, Point(0,0));
It looks like the problem ended up being Visual Studio related. After installing SP1 http://www.microsoft.com/en-us/download/details.aspx?id=23691 and making adjustments to the code as suggested by berak and vasan. The final code is below:
/* NOTE: Using namespace cv & std */
/* Get input image */
Mat origImg = imread("C:\\PathToImage\\Image.png", CV_LOAD_IMAGE_GRAYSCALE);
/* Threshold input image */
Mat threshImg;
threshold(origImg, threshImg, 150, 255.0, THRESH_BINARY);
/* Get contours from threshold image */
Mat copyImage = threshImg.clone();
vector<vector<Point>> contours;
findContours(copyImage, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, Point(0,0));
Related
I'm trying to get contour points with OpenCV
I'm using openCV 2411 because of my main application works 32 bit and newer versions of Opencv are 64 bit only. My code is;
Mat src = imread(filename,CV_LOAD_IMAGE_ANYDEPTH);
Mat gThreshold = Mat(src.rows, src.cols, CV_8U);
threshold(src, gThreshold,128, 255, CV_THRESH_BINARY);
imshow("thres", gThreshold);
waitKey(0);
Mat dst = Mat(src.rows, src.cols, CV_8UC4);
std::vector<std::vector<cv::Point> > contours;
vector<Vec4i> hierarchy;
findContours(gThreshold, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE);
int idx = 0;
for (; idx >= 0; idx = hierarchy[idx][0])
{
Scalar color(rand() & 255, rand() & 255, rand() & 255);
drawContours(dst, contours, idx, color,1, 8, hierarchy);
}
imshow("con", dst);
waitKey(0);
return 1;
Normally this code works with small images (smaller than 200x200 pixel) but I can't get any result bigger than this size. It crashes every time.But crashes after showing threshold and contour images.
I tried with different type of images but nothing changed.
I searched stackoverflow and there are some same problems but I tried everything in answers nothing changed again.
I use release mode and libraries are ok. Is this about working on 32 bit? or am I missing something?
I have an original image
if I use imfill in Matlab, the result is
But I use the following code in C++ as an attempt to mimic the imfill from Matlab:
cv::Mat BW = cv::imread("smallHoles.bmp", cv::IMREAD_GRAYSCALE);
cv::Mat edgesNeg = BW.clone();
cv::floodFill(edgesNeg, cv::Point(0, 0), cv::Scalar(255));
bitwise_not(edgesNeg, edgesNeg);
cv::Mat filledEdgesOut = (edgesNeg | BW);
cv::imwrite("C:/Users/me/circleCVfill.bmp", filledEdgesOut);
the result is that all the black objects, even the black vertical object, gets filled with white pixels, which doesn't match the Matlab result:
What is the correct C++ OpenCV code to use?
EDIT:
The Matlab code I use:
BW=imread('smallHoles.bmp');
BWfill=imfill(BW,'holes');
EDIT2:
I also tried the following code
cv::Mat circle = cv::imread("smallHoles.bmp", cv::IMREAD_GRAYSCALE);
std::vector<std::vector<cv::Point> > contours;
cv::Mat contourOutput = circle.clone();
cv::findContours(contourOutput, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
cv::Mat contourImage(circle.size(), CV_8UC1, cv::Scalar(255));
cv::drawContours(contourImage, contours, -1, cv::Scalar(255));
cv::imwrite("C:/Users/me/output.bmp", contourImage);
but it also gave just the same result of an all-white image just like the previous C++ code I tried
EDIT3:
I tried
std::vector<std::vector<cv::Point> > contours;
cv::Mat contourOutput = circle.clone();
cv::findContours(contourOutput, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
cv::drawContours(contourOutput, contours, -1, cv::Scalar(255));
cv::imwrite("C:/me/output.bmp", contourOutput);
It returns as output the original image with the 4 small black holes that should be filled
In trying your EDIT3:
cv::Mat circle = cv::imread(argv[1], cv::IMREAD_GRAYSCALE);
std::vector<std::vector<cv::Point> > contours;
cv::Mat contourOutput = circle.clone();
cv::findContours(contourOutput, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
cv::drawContours(contourOutput, contours, -1, cv::Scalar(255));
cv::imwrite("output.bmp", contourOutput);
I got the following:
https://i.stack.imgur.com/T5YBR.png
This is expected. If you check the documentation on the function drawContours, it says
thickness – Thickness of lines the contours are drawn with. If it is negative (for example, thickness=CV_FILLED ), the contour interiors are drawn.
So we can see the desired shapes are taken but the default for drawing is a thickness of one, but you want a negative value (or CV_FILLED) as the next parameter and you should get your desired solution.
I haven't used the floodFill function though, so can't help you there though.
I set up OpenCV with Visual Studio for a project and I am getting these really weird memory errors. I have been searching extensively for a fix to this, and while there are many similar questions, they are either unanswered or not working for me.
This is one of the few OpenCV functions I'm having problems with (got it from docs), which replicates the errors I get:
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace cv;
using namespace std;
Mat src; Mat src_gray;
int thresh = 100;
int max_thresh = 255;
RNG rng(12345);
/** #function main */
int main(int argc, char** argv)
{
/// Load source image and convert it to gray
std::string img = "<path-to-picture>";
src = imread(img, CV_LOAD_IMAGE_COLOR);
/// Convert image to gray and blur it
cvtColor(src, src_gray, CV_BGR2GRAY);
blur(src_gray, src_gray, Size(3, 3));
/// Create Window
char* source_window = "Source";
namedWindow(source_window, CV_WINDOW_AUTOSIZE);
imshow(source_window, src);
Mat canny_output;
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
/// Detect edges using canny
Canny(src_gray, canny_output, thresh, thresh * 2, 3);
/// Find contours
findContours(canny_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));
/// Draw contours
Mat drawing = Mat::zeros(canny_output.size(), CV_8UC3);
for (int i = 0; i< contours.size(); i++)
{
Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
drawContours(drawing, contours, i, color, 2, 8, hierarchy, 0, Point());
}
/// Show in a window
namedWindow("Contours", CV_WINDOW_AUTOSIZE);
imshow("Contours", drawing);
waitKey(0);
return(0);
}
Weird thing is that findContours() works perfectly, but after that the program crashes with this error:
Expression: "(_Ptr_user & (_BIG_ALLOCATION_ALIGNMENT - 1)) == 0" && 0
Any ideas on how to fix this? Here's my OpenCV setup:
Visual Studio 2015, Debug/Release x64
OpenCV 2.4.13 (pre-built)
C++ includes points to build\include
C++ linker points to \build\x64\vc12\lib
Dependencies includes libs in the above folder.
You're using OpenCV build with vc12 compiler (Visual Studio 2013), but in your project you're using vc14 (Visual Studio 2105).
Be sure to use the prebuild libs compiled with vc14.
I'm sure OpenCV 3.1 has prebuild binaries for vc14. I don't know if OpenCV 2.4.13 has them, too (probably not). In this case you need to recompile OpenCV with vc14, or switch to OpenCV 3.1
I have encounter this when I using findCountours() in OpenCV,
Debug Assertion Failed
I have google a lot but nothing helped me, following is part of my codes.
void HandTrack::ProcessFrame(...){
...
//Convert the colorImage into grayImage
Mat GrayImage;
cvtColor(ColorImages, GrayImage, CV_BGR2GRAY);
//Convert grayImage into binaryImage
Mat BinaryImage(GrayImage.rows, GrayImage.cols, CV_8UC1);
threshold(GrayImage, BinaryImage, 254, 255, CV_THRESH_BINARY);
bitwise_not(BinaryImage, BinaryImage);
//Get the contours from binaryImage
vector<vector<Point>> hand_contours;
findContours(BinaryImage, hand_contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE);
BinaryImage.release();
//Draw the contours
Mat OutlineImage(GrayImage.rows, GrayImage.cols, CV_8UC1);
rectangle(OutlineImage, Point(0, 0), Point(BinaryImage.cols, BinaryImage.rows), Scalar(255, 255, 255),-1,8);
if (hand_contours.size() > 0) {
drawContours(OutlineImage, hand_contours, -1, (0, 0, 0), 1);
}
waitkey(1);
}
Belows is what I've try:
Add imshow("img",BinaryImage); at last, and nothing change;
Comment this line↓, everything goes well
findContours(BinaryImage, hand_contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE);
Step through the codes, everything is well until the ‘}’ below the
waitkey(1);
}
Add hand_contours.~vector();(destruct fuction) before waitkey(1); the Debug Assertion Failed show wherever it are;
At last, I solved it by changing the local variable 'hand_contours' into global variable. But I still wondering why it solved. Thanks for read :)
ignore it,images in debuging
Your problem is somewhere in here:
//Convert the colorImage into grayImage
Mat GrayImage;
cvtColor(ColorImages, GrayImage, CV_BGR2GRAY);
//Convert grayImage into binaryImage
Mat BinaryImage(GrayImage.rows, GrayImage.cols, CV_8UC1);
threshold(GrayImage, BinaryImage, 254, 255, CV_THRESH_BINARY);
bitwise_not(BinaryImage, BinaryImage);
//Get the contours from binaryImage
vector<vector<Point>> hand_contours;
You created your BinaryImage to be CV_8UC1 which is good, but I have a feeling that your GrayImage is not ALWAYS going to be "...an 8-bit single-channel image." as required by the documentation. Somewhere along the way it probably doesn't get truncated correctly.
Your GrayImage was derived from a color image and probably occasionally has some empty channels. Check to make sure both your dst and src Mat's are the correct format (That is 99.9% of the time what an assertion failure is from).
As to how this issue got solved from changing a global? There's really no way to tell without seeing the rest of the code.
My best guess is that somehow it caused some of your functions to change the content of your MAT's to the format you intended before arrival at the function you showed us above. But there's really no way to tell without seeing it.
But, moral of the story is as long as you can check your src and dst are correctly formatted you will avoid most Assertion Failures.
I have been stuck with this issue for days;
I created a Qt console project, connected it with OpenCV and everything was working just fine;
I created a Qt Gui project, added a button and copied the same code from the previous project in the button's slot, I got a windows segFault and program exited with code -1073741819.
So I used the debugger to detect the problem and it turned out to be at the use of function cv::threshold.
I changed it and instead used cv::Canny but then I got the same problem with cv::findContours !
The strange thing is that when I called the button's 'MainWindow::on_pushButton_clicked()'
in the windows' constructor it worked!!!
here's debugger output:
0 cv::thresh_8u(cv::Mat const&, cv::Mat&, unsigned char, unsigned char, int) C:\OpenCV2.4\OpenMinGw\install\bin\libopencv_imgproc240.dll 0 0x62b2c624
1 cv::_InputArray::getMat(int) const C:\OpenCV2.4\OpenMinGw\install\bin\libopencv_core240.dll 0 0x65c1a838
2 ?? 0 0x00000000
and here's the function where I get the error (which I got from OpenCV tutorials):
void MainWindow::on_pushButton_clicked(){
Mat src; Mat src_gray;
int thresh = 100;
RNG rng(12345);
Mat canny_output;
vector<vector<Point> > contours;
/// Load source image and convert it to gray
src = imread( "hat-10.bmp", 1 );
cvtColor( src, src_gray, CV_BGR2GRAY );
blur( src_gray, src_gray, Size(3,3) );
/// Detect edges using canny
Canny( src_gray, canny_output, thresh, thresh*2, 3 );
qDebug("Ok 1");
/// Find contours
if(cv::sum(src_gray).val[0] > 0.0){
qDebug("Ok 2");
cv::findContours( src_gray, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE );
/// Draw contours
Mat drawing = Mat::zeros( src_gray.size(), CV_8UC3 );
for( int i = 0; i< contours.size(); i++ )
{
Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) );
drawContours( drawing, contours, i, color, 2);//, 8, hierarchy, 0, Point() );
}
/// Show in a window
imshow( "Contours", drawing);
}
Using:
Windows 7 x64
OpenCV 2.4.0 compiled using mingw 4.1.0
Qt Creator 2.0.0 Based on Qt 4.7.0 (32 bit)
Edit:
here's a shorter version of my code :
void MainWindow::on_toolButton_clicked(){
std::vector<std::vector<cv::Point> > contours;
/// Load source image and convert it to gray
Mat src = imread( "C:/Users/poste/L3 ISIL/PFE Licence/new bmp/hat-10.bmp", 1);
// my image is already a binary one
Mat canny_output(src.size(), src.type());
Canny(src,canny_output,100,200,3);
imshow("Source", canny_output); // here image is displayed before crash
waitKey(500);
/// Find contours
findContours(canny_output, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE );
}
in console mode, there's no problem. when called from GUI app constructor there's also no problem.
It only crashes when actually clicking on the button.
edit:
I took a screenshot ![here]http://i.stack.imgur.com/1LyeF.png
canny_output was displayed which means image was loaded.
Uploaded project here
First make sure that the image that you want to threshold is really a gray scaled image. Show it in another window after Thresholding.
Do that before cv::FindContours:
cvThreshold(originalImage,resultingImage,100,100,CV_THRESH_BINARY)
also change that:
vector<vector<Point> > contours;
to:
vector<vector<cv::Point2f> > contours;
Try this:
/// Load source image and convert it to gray
Mat src = imread( "hat-10.bmp", 1 );
Mat src_gray(src.size(), CV_8U);
cvtColor( src, src_gray, CV_BGR2GRAY );
blur( src_gray, src_gray, Size(3,3) );
//Apply threshold
cv::Mat thres_output(src_gray.size(), src_gray.type());
cv::threshold(src_gray, thres_output, 100, 255, cv::THRESH_BINARY);
qDebug("Ok 1");
OpenCV docs have a full demo on Basic Thresholding Operations.
EDIT:
After carefully reviewing your code and comments, I think I know what's going on: these problems might be happening because imread() can't access the specified file. This makes the function return an empty Mat. To check if this is the case, simply do:
Mat src = imread( "hat-10.bmp", 1 );
if (src.empty())
{
std::cout << "!!! imread failed to open image\n";
return;
}
The reason why it happens is because Qt Creator builds the .exe of the project in a separate folder, so when the application runs, it tries to load the image from the directory where the .exe was launched, and it fails because the image isn't there.
When calling imread() remember to pass the FULL PATH to the file. See if that fixes the issue.
EDIT:
Remember to convert the image to binary before feeding it to findContours():
// Convert from 32F to 8U
cv::Mat binary_img;
canny_output.convertTo(binary_img, CV_8U);
std::vector<std::vector<cv::Point> > contours;
cv::findContours(binary_img, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
I used function Qtconcurrent::run() and everything started working.
Even though this isn't a permanent (nor a good) solution; this is all I could come up with.
I'm still open to other answers though.