OpenCV finding contours - c++

The following code for finding contours in an image does not give any compilation errors. However, on running I get the error
"Open cv:Assertion failed (size.width > 0 && size.height > 0)" in the OpenCV imshow file.
I tried the code with just the imshow function, removing everything after it, and the code runs fine, hence the file location does not seem to be a problem!
Any help would be much appreciated.
Thanks in advance!
#include <opencv\cv.h>
#include <opencv2\highgui\highgui.hpp>
#include <opencv\cvaux.h>
#include <opencv\cxcore.h>
#include <opencv2\imgproc\imgproc.hpp>
#include <iostream>
#include <conio.h>
using namespace cv;
using namespace std;
int main() {
Mat img1;
Mat output;
Mat img = imread("blue.jpg");
cvtColor(img, img1, CV_BGR2GRAY);
threshold(img1, output, 176, 255, CV_THRESH_BINARY);
imshow("hi", output);
vector<vector<Point>> Contours;
vector<Vec4i> hier;
Mat final;
findContours(img1, Contours, hier, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
for (int i = 0; i < Contours.size(); i++)
{
drawContours(final, Contours, i, Scalar(0, 255, 0), 1, 8, hier);
}
imshow("result", final);
waitKey();
}

You are drawing to a non initialized matrix (final) here:
Mat final;
....
drawContours(final, Contours, i, Scalar(0, 255, 0), 1, 8, hier);
You should initialize final first, like:
Mat final = img.clone();

Related

C++ OpenCV - Find biggest object in an webcam stream and sort it by size

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.

OpenCV Weird Memory Corruption

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

Cleaning a segmented image in Opencv

I have this original:
After segmentation I obtained this image:
As you can see it is still not perfectly segmented. Any suggestions on how to further "clean" this segmented image? Here is my code:
using namespace cv;
using namespace std;
Mat COLOR_MAX(Scalar(65, 255, 255));
Mat COLOR_MIN(Scalar(15, 45, 45));
int main(int argc, char** argv){
Mat src,src2,hsv_img,mask,gray_img,initial_thresh,second_thresh,add_res,and_thresh,xor_thresh,result_thresh,rr_thresh,final_thresh;
// Load source Image
src = imread("banana2.jpg");
src2 = imread("Balanced_Image1.jpg");
imshow("Original Image", src);
cvtColor(src,hsv_img,CV_BGR2HSV);
imshow("HSV Image",hsv_img);
//imwrite("HSV Image.jpg", hsv_img);
inRange(hsv_img,COLOR_MIN,COLOR_MAX, mask);
imshow("Mask Image",mask);
cvtColor(src,gray_img,CV_BGR2GRAY);
adaptiveThreshold(gray_img, initial_thresh, 255,ADAPTIVE_THRESH_GAUSSIAN_C, CV_THRESH_BINARY_INV,257,2);
imshow("AdaptiveThresh Image", initial_thresh);
add(mask,initial_thresh,add_res);
erode(add_res, add_res, Mat(), Point(-1, -1), 1);
dilate(add_res, add_res, Mat(), Point(-1, -1), 5);
imshow("Bitwise Res",add_res);
threshold(gray_img,second_thresh,150,255,CV_THRESH_BINARY_INV | CV_THRESH_OTSU);
imshow("TreshImge", second_thresh);
bitwise_and(add_res,second_thresh,and_thresh);
imshow("andthresh",and_thresh);
bitwise_xor(add_res, second_thresh, xor_thresh);
imshow("xorthresh",xor_thresh);
bitwise_or(and_thresh,xor_thresh,result_thresh);
imshow("Result image", result_thresh);
bitwise_and(add_res,result_thresh,final_thresh);
imshow("Final Thresh",final_thresh);
erode(final_thresh, final_thresh, Mat(), Point(-1,-1),6);
bitwise_or(src,src,rr_thresh,final_thresh);
imshow("Segmented Image", rr_thresh);
imwrite("Segmented Image.jpg", rr_thresh);
waitKey(0);
return 1;
}`
Sorry for Python, it was easier to prototype and shouldn't be too difficult to port to C++.
import cv2
import numpy as np
img = cv2.imread("banana.jpg", 0)
edges = cv2.Canny(img, 10, 100)
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))
dilated = cv2.dilate(edges,kernel,iterations = 1)
contours, hierarchy = cv2.findContours(dilated, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
for i,contour in enumerate(contours):
area = cv2.contourArea(contour)
if area > 1000.0:
cv2.drawContours(img, contours, i, (0,255,255), 2)
cv2.imwrite('banana_out.png', img)
I used Canny edge detection, since the edges of the banana seem pretty sharp. I filled some of the gaps in using dilation on the mask. This could probably be done better.
Input:
Edges:
Dilated edges:
Output:
C++ Version
#include <opencv2/opencv.hpp>
int main(int argc, char** argv)
{
cv::Mat img = cv::imread("./banana.jpg");
cv::Mat gray_img;
cv::cvtColor(img, gray_img, CV_BGR2GRAY);
cv::Mat edges;
cv::Canny(gray_img, edges, 10, 100);
cv::Mat kernel = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(5, 5));
cv::Mat dilated;
cv::dilate(edges, dilated, kernel);
std::vector<std::vector<cv::Point>> contours;
std::vector<cv::Vec4i> hierarchy;
cv::findContours(dilated, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
cv::Mat mask = cv::Mat::zeros(gray_img.size(), CV_8UC1);
double const MIN_CONTOUR_AREA(1000.0);
for (int i(0); i < contours.size(); ++i) {
double area = cv::contourArea(contours[i]);
if (area >= MIN_CONTOUR_AREA) {
cv::drawContours(mask, contours, i, cv::Scalar(255, 255, 255), CV_FILLED);
}
}
cv::Mat eroded;
cv::erode(mask, eroded, kernel);
cv::Mat masked_object;
cv::bitwise_and(img, img, masked_object, eroded);
cv::imwrite("banana_out.png", masked_object);
return 1;
}
Output:
Perhaps if you did an intersection of my mask and yours, you'd get even better result...

Ignore connected component inside another one

I'm trying to separate the background (green field and light green towel) from the objects using OpenCV so I segmented the following image manually:
By bordering the objects in red and coloring blue the connected components which should not be taken into consideration as you can see in the bottom right of the image:
After threasholding on 254 the channels R and B, I got the following:
Channel Red
Channel Blue
If I fulfill the all contours of red channel using
findContours( bordersRed, contoursRedChannel, hierarchyRedChannel, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, cv::Point(0, 0) );
for (int index = 0; index < contoursRedChannel.size(); index ++)
{
drawContours( bordersRed, contoursRedChannel, index, colorForMask, CV_FILLED, 8, hierarchyRedChannel, 0, cv::Point() );
}
the bottom right corner will be like:
But what I need is to ignore the contours that contains only blue points in order to have something like:
so I have to combine the red with blue channels to get it but don't know how yet. Any advice would be appreciated.
Thanks.
You can do that using floodFill, assuming you know a point inside the shape you want to fill.
Result starting from your "Channel red":
Code:
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main()
{
// Your image
Mat1b img = imread("path_to_image", IMREAD_GRAYSCALE);
// Assume you know a point inside the shape
Point seed(930, 370);
// Apply floodfill
floodFill(img, seed, Scalar(255));
// Show image
imshow("Result", img);
waitKey();
return 0;
}
UPDATE
Once you fill the contours in both masks with drawContours(... CV_FILLED), you can simply XOR the two mask:
Code:
#include <opencv2\opencv.hpp>
#include <vector>
#include <algorithm>
using namespace std;
using namespace cv;
int main()
{
// Load the two mask
Mat1b channel_red_mask = imread("channel_red.png", IMREAD_GRAYSCALE);
Mat1b channel_blue_mask = imread("channel_blue.png", IMREAD_GRAYSCALE);
// Use just the bottom right part
Rect roi(Point(800, 270), Point(channel_red_mask.cols, channel_red_mask.rows));
channel_red_mask = channel_red_mask(roi).clone();
channel_blue_mask = channel_blue_mask(roi).clone();
// Fill all contours, in both masks
{
vector<vector<Point>> contours;
findContours(channel_red_mask.clone(), contours, RETR_LIST, CHAIN_APPROX_SIMPLE);
for (int i = 0; i < contours.size(); ++i)
{
drawContours(channel_red_mask, contours, i, Scalar(255), CV_FILLED);
}
}
{
vector<vector<Point>> contours;
findContours(channel_blue_mask.clone(), contours, RETR_LIST, CHAIN_APPROX_SIMPLE);
for (int i = 0; i < contours.size(); ++i)
{
drawContours(channel_blue_mask, contours, i, Scalar(255), CV_FILLED);
}
}
// XOR the masks
Mat1b xored = channel_red_mask ^ channel_blue_mask;
imshow("XOR", xored);
waitKey();
return 0;
}

OpenCV: contourArea assertion failed

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.