when I try to start my application it crashes unexpectedly while executing contourArea.
Here is the error:
OpenCV Error: Assertion Failed (contour.checkVector(2) >= 0 && (contour.depth() ==CV_32F || contour.depth() == CV_32S)) in unknown function, file ..\..\..\src\opencv\modules\imgproc\src\contours.cpp, line 1904
My program is simple:
1.catch frame from camera,
2. gaussian and median filtering,
3. morphological opening,
4. threshold,
5. findContours,
6. draw the contourn with bigger area
Here is my code:
#include <opencv2/opencv.hpp>
#include <stdio.h>
using namespace cv;
using namespace std;
Mat mask(480,640, CV_8UC1);
vector<Vec4i> hierarchy;
vector<vector<Point> > contours;
vector<Point> my_contourn;
int main(){
VideoCapture camera(0);
if(!camera.isOpened()){
return -1;
}
while(1){
Mat cameraframe,filtered_img,mask2;
camera >> cameraframe;
GaussianBlur(cameraframe,filtered_img,Size(11,11),0,0);
medianBlur(filtered_img,filtered_img,11);
cvtColor(filtered_img,filtered_img,CV_BGR2HSV);
inRange(filtered_img, Scalar(0, 76, 97), Scalar(20, 143, 205), mask);
morphologyEx(mask,mask,MORPH_OPEN,getStructuringElement(MORPH_RECT,Size(9,9),Point(4,4)));
GaussianBlur(mask,mask,Size(3,3),0,0);
dilate(mask,mask,getStructuringElement(MORPH_ELLIPSE,Size(7, 7),Point(0, 0) ));
mask.copyTo(mask2);
findContours(mask2,contours,hierarchy,CV_RETR_EXTERNAL,CV_CHAIN_APPROX_SIMPLE,Point(0, 0));
double area,max_area=0.0;
for(int i=0;i<contours.size();i++){
area = fabs(contourArea(contours[i]));
if (area>max_area)
{
max_area=area;
my_contourn=contours[i];
}
}
drawContours( mask, my_contourn, 10, Scalar(255,0,0), 2, 8);
imshow("my cont",mask);
if(waitKey(30)>=0)
break;
}
return 0;
}
How I can fix it??
I confirm that is a VS2012 problem. On VS2010 everythings is fine.
This wierd bug also occurs on VS2013.
Try converting the type of contours[i] from vector to CV::Mat before pass it to contourArea.
Mat conMat(contours[i].size(), 2, CV_32FC1);
for(int i = 0; i < contours[i].size(); i ++)
{
conMat.at<float>(i, 0) = contours[i].x;
conMat.at<float>(i, 1) = contours[i].y;
}
area = fabs(contourArea(conMat));
That works for me.
Related
I'm currently having a nasty bug I don't know how to fix myself that only started up when I started not using the debug mode in Visual Studio 2017 and went to release. I'm trying to get my openCV code to recognize checkerboard corners to help calibrate the camera based off of this example: http://aishack.in/tutorials/calibrating-undistorting-opencv-oh-yeah/ Here is the code I specifically have:
// ConsoleApplication2.cpp : Defines the entry point for the console
application.
//
#include "stdafx.h"
#include <opencv2\videoio.hpp>
#include <opencv2\highgui.hpp>
#include <opencv\cv.hpp>
#include <opencv\cv.h>
#include <iostream>
#include <stdio.h>
using namespace cv;
using namespace std;
int main (){
int numBoards = 0;
int numCornersHor;
int numCornersVer;
printf("Enter number of corners along width: ");
scanf_s("%d", &numCornersHor);
printf("Enter number of corners along height: ");
scanf_s("%d", &numCornersVer);
printf("Enter number of boards: ");
scanf_s("%d", &numBoards);
int numSquares = numCornersHor * numCornersVer;
Size board_sz = Size(numCornersHor, numCornersVer);
VideoCapture capture = VideoCapture("rtsp://172.16.127.28:554/mpeg4");
vector<vector<Point3f>> object_points;
vector<vector<Point2f>> image_points;
vector<Point2f> corners;
int successes = 0;
Mat image;
Mat gray_image;
capture >> image;
vector<Point3f> obj;
for (int j = 0; j < numSquares; j++)
obj.push_back(Point3f(j / numCornersHor, j%numCornersHor, 0.0f));
while (successes < numBoards) {
cvtColor(image, gray_image, CV_BGR2GRAY);
bool found = findChessboardCorners(image, board_sz, corners, CV_CALIB_CB_ADAPTIVE_THRESH | CV_CALIB_CB_FILTER_QUADS);
if (found) {
cornerSubPix(gray_image, corners, Size(11,11), Size(-1, -1), TermCriteria(CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 30, 0.1));
drawChessboardCorners(gray_image, board_sz, corners, found);
}
imshow("win1", image);
imshow("win2", gray_image);
capture >> image;
int key = waitKey(1);
if (key == 27)
return 0;
if (key == ' ' && found != 0){
image_points.push_back(corners);
object_points.push_back(obj);
printf("Snap stored!");
successes++;
if (successes >= numBoards)
break;
}
}
Mat intrinsic = Mat(3, 3, CV_32FC1);
Mat distCoeffs;
vector<Mat> rvecs;
vector<Mat> tvecs;
intrinsic.ptr<float>(0)[0] = 1;
intrinsic.ptr<float>(1)[1] = 1;
calibrateCamera(object_points, image_points, image.size(), intrinsic, distCoeffs, rvecs, tvecs);
Mat imageUndistorted;
while (1) {
capture >> image;
undistort(image, imageUndistorted, intrinsic, distCoeffs);
imshow("win1", image);
imshow("win2", imageUndistorted);
waitKey(1);
}
capture.release();
return 0;
}
Here is the output I end up getting:
warning: Error opening file
(/build/opencv/modules/videoio/src/cap_ffmpeg_impl.hpp:834)
warning: rtsp://172.16.127.28:554/mpeg4
(/build/opencv/modules/videoio/src/cap_ffmpeg_impl.hpp:835)
OpenCV(3.4.1) Error: Assertion failed (scn == 3 || scn == 4) in cv::cvtColor,
file C:\build\master_winpack-build-win64-
vc15\opencv\modules\imgproc\src\color.cpp, line 11147
This only really started being an issue when I went to the release mode instead of debug and I don't know what exactly is going on here. I would like a specific answer obviously, but even just a general direction that specifically applies to this case would be much appreciated, if any more details are needed, I'll gladly add them to this post. I'm still new to C++, Visual Studio, and OpenCV, so please keep that in mind.
Edit: it's odd how it's referencing a file path that doesn't exist too, there's no build folder in the C:/ directory unless it's referencing something in my include path maybe?
Edit 2: The answer for OpenCV Error: Assertion failed (scn == 3 || scn == 4) in cv:: cvtColor, file ..\..\..\..\opencv\modules\imgproc\src\color.cpp, line 3737 did not solve my problem, trying that solution yields new errors:
warning: Error opening file
(/build/opencv/modules/videoio/src/cap_ffmpeg_impl.hpp:834)
warning: rtsp://172.16.127.28:554/mpeg4
(/build/opencv/modules/videoio/src/cap_ffmpeg_impl.hpp:835)
OpenCV(3.4.1) Error: Assertion failed (dims <= 2 && step[0] > 0) in
cv::Mat::locateROI, file C:\build\master_winpack-build-win64-
vc15\opencv\modules\core\src\matrix.cpp, line 760
I should also mention that the exception in all cases according to visual studio happens on line 52 of my main.cpp:
bool found = findChessboardCorners(image, board_sz, corners,
CV_CALIB_CB_ADAPTIVE_THRESH | CV_CALIB_CB_FILTER_QUADS);
It turns out in the rtsp stream, I was trying to fetch a video stream from an IP that was down, causing the exception since there was no image to process. I swapped it to one that was up and verified it worked on release and debug, thanks for all your help!
My goal is to find the biggest contour of a captured webcam frame, then after it's found, find its size and determine either to be rejected or accepted.
Just to explain the objetive of this project, i am currently working for a Hygiene product's Manufacturer. There we have, in total, 6 workers that are responsible for sorting the defective soap bars out of the production line. So in order to gain this workforce for other activities, i am trying to write an algorithm to "replace" their eyes.
I've tried several methods along the way (findcontours, SimpleBlobDetection, Canny, Object tracking), but the problem that i've been facing is that i can't seem to find a way to effectively find the biggest object in a webcam image, find its size and then determine to either discard or accept it.
Below follows my newest code to find the biggest contour in an webcam stream:
#include <iostream>
#include "opencv2/highgui/highgui.hpp"
#include "opencv/cv.h"
#include "opencv2\imgproc\imgproc.hpp"
using namespace cv;
using namespace std;
int main(int argc, const char** argv)
{
Mat src;
Mat imgGrayScale;
Mat imgCanny;
Mat imgBlurred;
/// Load source image
VideoCapture capWebcam(0);
if (capWebcam.isOpened() == false)
{
cout << "Não foi possível abrir webcam!" << endl;
return(0);
}
while (capWebcam.isOpened())
{
bool blnframe = capWebcam.read(src);
if (!blnframe || src.empty())
{
cout << "Erro! Frame não lido!\n";
break;
}
int largest_area = 0;
int largest_contour_index = 0;
Rect bounding_rect;
Mat thr(src.rows, src.cols, CV_8UC1);
Mat dst(src.rows, src.cols, CV_8UC1, Scalar::all(0));
cvtColor(src, imgGrayScale, CV_BGR2GRAY); //Convert to gray
GaussianBlur(imgGrayScale, imgBlurred, Size(5, 5), 1.8);
Canny(imgBlurred, imgCanny, 45, 90); //Threshold the gray
vector<vector<Point>> contours; // Vector for storing contour
vector<Vec4i> hierarchy;
findContours(imgCanny, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE); // Find the contours in the image
for (int i = 0; i < contours.size(); i++) // iterate through each contour.
{
double a = contourArea(contours[i], false); // Find the area of contour
if (a > largest_area)
{
largest_area = a;
largest_contour_index = i; //Store the index of largest contour
bounding_rect = boundingRect(contours[i]); // Find the bounding rectangle for biggest contour
}
}
Scalar color(255, 255, 255);
drawContours(dst, contours, largest_contour_index, color, CV_FILLED, 8, hierarchy); // Draw the largest contour using previously stored index.
rectangle(src, bounding_rect, Scalar(0, 255, 0), 1, 8, 0);
imshow("src", src);
imshow("largest Contour", dst);
waitKey(27);
}
return(0);
}
And here are the results windows that the program generates and the image of the object that i want to detect and sort.
Thank you all in advance for any clues on how to achieve my goal.
I'm trying to count object from image. I use logs photo, and I use some steps to get a binary image.
This is my code:
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
#include <features2d.hpp>
using namespace cv;
using namespace std;
int main(int argc, char *argv[])
{
//load image
Mat img = imread("kayu.jpg", CV_LOAD_IMAGE_COLOR);
if(img.empty())
return -1;
//namedWindow( "kayu", CV_WINDOW_AUTOSIZE );
imshow("kayu", img);
//convert to b/w
Mat bw;
cvtColor(img, bw, CV_BGR2GRAY);
imshow("bw1", bw);
threshold(bw, bw, 40, 255, CV_THRESH_BINARY);
imshow("bw", bw);
//distance transform & normalisasi
Mat dist;
distanceTransform(bw, dist, CV_DIST_L2, 3);
normalize(dist, dist, 0, 2., NORM_MINMAX);
imshow("dist", dist);
//threshold to draw line
threshold(dist, dist, .5, 1., CV_THRESH_BINARY);
imshow("dist2", dist);
//dist = bw;
//dilasi
Mat dilation, erotion, element;
int dilation_type = MORPH_ELLIPSE;
int dilation_size = 17;
element = getStructuringElement(dilation_type, Size(2*dilation_size + 1, 2*dilation_size+1), Point(dilation_size, dilation_size ));
erode(dist, erotion, element);
int erotionCount = 0;
for(int i=0; i<erotionCount; i++){
erode(erotion, erotion, element);
}
imshow("erotion", erotion);
dilate(erotion, dilation, element);
imshow("dilation", dilation);
waitKey(0);
return 0;
}
As you can see, I use Erosion and Dilation to get better circular object of log. My problem is, I'm stuck at counting the object. I tried SimpleBlobDetector but I got nothing, because when I try to convert the result of "dilation" step to CV_8U, the white object disappear. I got error too when I use findContours(). It say something about channel of image. I can't show the error here, because that's too many step and I already delete it from my code.
Btw, at the end, i got 1 channel of image.
Can i just use it to counting, or am i have to convert it and what is the best method to do it?
Two simple steps:
Find contours for the binarized image.
Get the count of the contours.
Code:
int count_trees(const cv::Mat& bin_image){
cv::Mat img;
if(bin_image.channels()>1){
cv::cvtColor(bin_image,img,cv::COLOR_BGR2GRAY);
}
else{
img=bin_image.clone();;
}
if(img.type()!=CV_8UC1){
img*=255.f; //This could be stupid, but I do not have an environment to try it
img.convertTo(img,CV_8UC1);
}
std::vector<std::vector<cv::Point>> contours
std::vector<Vec4i> hierarchy;
cv::findContours( img, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
return contours.size();
}
I have the same problem, here's an idea I'm about to implement.
1) Represent your image as an array of integers; 0 = black, 1 = white.
2) set N = 2;
3) Scan your image, pixel-by-pixel. Whenever you find a white pixel, activate a flood-fill algorithm, starting at the pixel just found; paint the region with the value of N++;
4) Iterate 3 until you reach the last pixel. (N-2) is the number of regions found.
This method depends on the shape of the objects; mine are more chaotic than yours (wish me luck..). I'll make use of a recursive flood-fill recipe found somewhere (maybe Rosetta Code).
This solution also makes it easy to compute the size of each region.
try to apply that on the your deleted img
// count
for (int i = 0; i< contours.size(); i = hierarchy[i][0]) // iteration sur chaque contour .
{
Rect r = boundingRect(contours[i]);
if (hierarchy[i][2]<0) {
rectangle(canny_output, Point(r.x, r.y), Point(r.x + r.width, r.y + r.height), Scalar(20, 50, 255), 3, 8, 0);
count++;
}
}
cout << "Numeber of contour = " << count << endl;
imshow("src", src);
imshow("contour", dst);
waitKey(0);
I'm pretty new to OpenCV and having a slight problem which is probably something very easy to fix.
Basically im doing some basic image processing, I'm trying to find contours which have an contourArea() of < 3000.
The problem is, I'm getting the following error when trying to draw contours and/or call contourArea() function:
The error is occuring on the cv:contourArea() line, the error message is:
OpenCV Error: Assertion failed (contour.checkVector(2) >= 0 && (contour.depth() == CV_32F || contour.depth() == CV_32S)) in cv::contourArea,
file ..\..\..\..\opencv\modules\imgproc\src\contours.cpp, line 1904
Any help is greatly appreciated. The code is below:
using namespace cv;
cv::Mat greyMat, binaryMat, newMat;
cv::Mat image = cv::imread("image.png", 1);
// First convert image to gray scale
cv::cvtColor(image, greyMat, CV_BGR2GRAY);
cv::adaptiveThreshold(greyMat, binaryMat, 255, cv::ADAPTIVE_THRESH_GAUSSIAN_C, cv::THRESH_BINARY_INV, 45, 0);
erode(binaryMat, binaryMat, getStructuringElement(MORPH_ELLIPSE, Size(2, 2)));
dilate(binaryMat, binaryMat, getStructuringElement(MORPH_ELLIPSE, Size(1, 1)));
// Remove unclosed curves (the circled hashtag)
cv::copyMakeBorder(binaryMat, newMat, 1, 1, 1, 1, cv::BORDER_CONSTANT, 0);
cv::floodFill(newMat, cv::Point(0, 0), 255);
newMat = 255 - newMat;
cv::Mat cMat;
newMat.copyTo(cMat);
std::vector<std::vector<cv::Point>> contours;
cv::findContours(cMat, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE);
std::cout << "Found: " << contours.size() << " " << contours[0][0] << std::endl;
for (size_t i = 0; i < contours.size(); i++)
{
if (cv::contourArea(contours[i]) < 3000)
{
cv::drawContours(newMat, contours, i, 255, -1);
}
}
cv::imshow("Debug", newMat);
cv::waitKey(0);
return 0;
Not sure, but from what I read in the error message, the function expects a floating point value, and you give him vector of vector of Point.
According to the current manual, this type is an integer point, so maybe this is the problem.
I've been trying to set up a program that uses HSV to detect a specific colour and place a rectangle around the biggest area found of said colour. I am having problems when i get to the vectors and the "findContours" function, which stops the program with an error stating "xxx.exe has triggered a break point".
This only happens when I insert the line
findContours(dilatedBlue,contours,hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE);
I'm a rookie when it comes to OpenCV and C++ but I'm hoping someone will be able to help. I'm using windows 7 x64, Visual Studio 2012 and OpenCV 2.4.8.
My full code is what follows:
#include "stdafx.h"
#include <opencv2/core/core.hpp> // Basic OpenCV structures (cv::Mat, Scalar)
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace cv;
int _tmain(int argc, _TCHAR* argv[])
{
VideoCapture cap(0); // open the default camera
if(!cap.isOpened()) // check if we succeeded
return -1;
// Declare Local Variables
int Quit = 0;
Mat imageDiff;
Mat HSVMatrix[3];
Mat erodedBlue;
Mat dilatedBlue;
//Start of search/shoot routine
while( Quit != 'q' ) // For as long as User wishes to continue...
{
Mat image;
cap >> image; // get a new frame from camera
imshow("Original", image);
//GaussianBlur(image, image, Size(3,3), 1.5, 1.5); // Setting up a Gaussian blur using 5x5 grid
cvtColor(image, imageDiff, CV_BGR2HSV);
split(imageDiff,HSVMatrix);
//Setting up saturation values for colour blue
threshold(HSVMatrix[0],HSVMatrix[0],130,255,THRESH_TOZERO_INV); // High value of colour - Dynamic changing of variable to select mode 130
threshold(HSVMatrix[0],HSVMatrix[0],75,255,THRESH_BINARY); // Low value of colour 75
threshold(HSVMatrix[1],HSVMatrix[1],255,255,THRESH_TOZERO_INV); // High saturation value - Modify for varying levels of light
threshold(HSVMatrix[1],HSVMatrix[1],100,255,THRESH_BINARY); // Low saturation value
HSVMatrix[2]=HSVMatrix[1]&HSVMatrix[0];
imshow("HSVblue", HSVMatrix[2]); // Displays binarised image
erode(HSVMatrix[2], HSVMatrix[2], Mat(), Point(-1, -1), 2, 1, 1);
erode(HSVMatrix[2], erodedBlue, Mat(), Point(-1, -1), 2, 1, 1);
imshow("Eroded-Blue", erodedBlue);
dilate(erodedBlue, dilatedBlue, Mat(), Point(-1, -1), 2, 1, 1);
imshow("Dilated-Blue", dilatedBlue);
vector<vector<Point> > contours; // Temporary variables used to hold contour information
vector<Point> approx;
vector<Vec4i> hierarchy;
vector<Rect> boundRect(contours.size());
findContours(dilatedBlue,contours,hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE);
for (int i = 0; i < contours.size(); i++)
{
approxPolyDP(Mat(contours[i]), approx, arcLength(Mat(contours[i]), true) * 0.02, true); // Calculation of contours and their approximate size and sides
}
for (int i = 0; i < contours.size(); i++)
{
if ((approx.size() == 4) && (fabs(contourArea(Mat(approx))) > 100)) // The properties that have to be fulfilled in order for the object to be recognized by the computer
{
Rect outline; // If the properties have been fulfilled and the object has been recognized, display an outline around the object
outline = boundingRect(approx);
rectangle(image,Rect(outline),Scalar(0, 255, 255),5,8,0); // The properties of the outline: the colour[bgr] and thickness
}
}
imshow("Target", image);
}
Quit = cvWaitKey(1); // The program waits for the key "q" to be pressed to exit
}
cap.release();
return 0;
}