OpenCV 2.4.9 function findContours() causes program to crash - c++

The code looks like that:
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <stdio.h>
#include<time.h>
using namespace cv;
using namespace std;
int main()
{
Mat image, edges, src_gray, output;
int largest_area = 0;
int largest_contour_index = 0;
Rect bounding_rect;
string Destination = "F:\\vision_systems\\NoveltyDetectionData\\Set3\\TRAINING_DATA\\m_DSC_0030_m.jpg";
image = imread(Destination, CV_LOAD_IMAGE_COLOR);
Mat dst(image.rows, image.cols, CV_8UC1, Scalar::all(0));
cvtColor(image, src_gray, CV_BGR2GRAY);
blur(src_gray, src_gray, Size(3, 3));
Canny(src_gray, edges, 80, 200, 3);
threshold(edges, output, 100, 255, THRESH_BINARY);
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
vector<Rect> boundRect(contours.size());
findContours(output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE);
Mat drawing = Mat::zeros(edges.size(), CV_8UC3);
for (int i = 0; i< contours.size(); i++)
{
double a = contourArea(contours[i], false);
if (a>largest_area) {
largest_area = a;
largest_contour_index = i;
bounding_rect = boundingRect(contours[i]);
}
}
Scalar color(255, 255, 255);
drawContours(dst, contours, largest_contour_index, color, CV_FILLED, 8, hierarchy);
rectangle(image, bounding_rect, Scalar(0, 255, 0), 1, 8, 0);
imshow("src", image);
imshow("largest Contour", output);
Mat roiImg;
roiImg = image(bounding_rect);
imshow("roiIMG", roiImg);
waitKey(0);
}
It is supposed to cut the region of interest where the contours are detected, leaving the background which i dont need.
The code works on the computer with OpenCV 3.1, it is a little bit modified code from OpenCV documentation.
The error is as follows:
Microsoft Visual Studio C Runtime Library has detected a fatal error in ConsoleApplication2.exe.
Press Break to debug the program or Continue to terminate the program.
and the debugger points to the line:
__scrt_debugger_hook_flag = 0;
No idea how to tackle this one, is it because my libraries are incorrectly installed or is it some rookie mistake in the code?
Cheers

Related

How to Enlarge each rectangle (boundingbox) from findcontour Opencv C++

I have a program to detect an Image using bounding box. But, somehow only the center of the image (which have a high saturation) can detect. I want to enlarge the bounding box so the object with low saturation can be detect too.Here is the image image result
The red rectangle is the result of boundingbox from findcontour. I want the rectangle like the blue one, so the large object can be detected. Here is my code:
#include "stdafx.h"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
using namespace cv;
using namespace std;
int main(){
Mat frame = imread("32.jpg", 1);
Mat mask(frame.size(), CV_8UC1, Scalar::all(0));
Mat hsv;
int a = 5;
cv::cvtColor(frame, hsv, CV_BGR2HSV);
std::vector<cv::Mat> channels;
split(hsv, channels);
cv::Mat H = channels[0];
cv::Mat S = channels[1];
cv::Mat V = channels[2];
Mat th;
threshold(S, th, 90, 255, THRESH_OTSU);
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
/// Find contours
findContours(th, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_NONE, Point(0, 0));
vector<Rect> rekt(contours.size());
/// Draw contours
Mat drawing = Mat::zeros(th.size(), CV_8UC3);
for (int i = 0; i< contours.size(); i++)
{
if (cv::contourArea(contours[i]) < 500) continue;
rekt[i] = boundingRect(Mat(contours[i]));
rectangle(mask, rekt[i].tl(), rekt[i].br(), Scalar(0, 0, 255), 2, 8, 0);
}
imshow("ori", frame);
imshow("olaaa", resImage);
waitKey(0);
}
I have tried the other code such as here and this here but the image doesn't show the rectangle and only show black background.
Thankyou.

How to detect triangle accurately in OpenCv using C++

I am detecting red triangle objects in real time video using OpenCv c++. But my program is not working properly. Whether I cannot use findContours or approxPolyDP not much well. Here is my code
#include "opencv2/opencv.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>
#include <raspicam/raspicam_cv.h>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace cv;
using namespace std;
int thresh = 100;
int number_pixels;
void drawAllTriangles(Mat&, const vector< vector<Point> >&);
int main(){
//Vectors
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
Mat canny_output,drawing;
//Initialise the image as a matrix container
Mat bgr;
raspicam::RaspiCam_Cv capture; // initialise the raspicam object
capture.open(); // activate the raspicam object
while (1)
{
capture.grab(); //grab the scene using raspicam
capture.retrieve(bgr); // retrieve the captured scene as an image and store it in matrix container
Mat gray,hsv; //Initialise the matrix container for gray color image
resize(bgr, bgr, Size(), .25, 0.25, CV_INTER_AREA);
//cvtColor(bgr, gray, COLOR_BGR2GRAY); //OpenCV code line for converting COLOR to GRAY scale image
//
cvtColor(bgr, hsv, COLOR_BGR2HSV);
//Gaussian Noice
Mat blure;
GaussianBlur(hsv,blure,Size(9,9),1.0);
//Gaussian Noice End
Mat mask1, mask2;
inRange(blure, Scalar(0,70,50), Scalar(10, 255, 255), mask1);
inRange(blure, Scalar(170, 70, 50), Scalar(180, 255, 255), mask2);
Mat mask3 = mask1 | mask2;
//Mat mask3 = mask1;
//
number_pixels = countNonZero(mask3);
Canny(mask3, canny_output, thresh, thresh*2, 3 );
findContours( canny_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );
drawing = Mat::zeros( canny_output.size(), CV_8UC3 );
imshow("Original frame", bgr); //displaying original frame
imshow("Gray frame", mask3); //displaying original frame
drawAllTriangles(drawing,contours);
imshow("Triangles",drawing);
if (cvWaitKey(20) == 'q') // waitkey
break;
}
capture.release(); // release the raspicam frame grabbing
return 0;
}
void drawAllTriangles(Mat& img, const vector< vector<Point> >& contours){
vector<Point> approxTriangle;
for(size_t i = 0; i < contours.size(); i++){
approxPolyDP(contours[i], approxTriangle, arcLength(Mat(contours[i]), true)*0.05, true);
if(approxTriangle.size() == 3 and number_pixels>200){
drawContours(img, contours, i, Scalar(0, 255, 255), CV_FILLED); // fill GREEN
vector<Point>::iterator vertex;
for(vertex = approxTriangle.begin(); vertex != approxTriangle.end(); ++vertex){
circle(img, *vertex, 3, Scalar(0, 0, 255), 1);
}
printf("Triangle \n");
}
else {
printf("None \n");
}
}
}
My program should detect any red triangle shaped objects in video. Where I am going wrong. Thank you for answer
THese are the images, but it cannot detect triangles and confusing.

Detect rectangles drawn on an background image using OpenCV

I’m trying to detect some rectangles (white colored) which is drawn on an image. (say using paint or some other image editing tool).
As I’m very much beginner to image processing I searched through net and OpenCV sample program to accomplish the job, but could not get it to working perfectly. I’m using OpenCV C++ library.
Algorithm that I’ve tried
cv::Mat src = cv::imread(argv[1]);
cv::Mat gray;
cv::cvtColor(src, gray, CV_BGR2GRAY);
meanStdDev(gray, mu, sigma);
cv::Mat bw;
cv::Canny(gray, bw, mu.val[0] - sigma.val[0], mu.val[0] + sigma.val[0]);
std::vector<std::vector<cv::Point> > contours;
cv::findContours(bw.clone(), contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
std::vector<cv::Point> approx;
for (int i = 0; i < contours.size(); i++){
cv::approxPolyDP(cv::Mat(contours[i]), approx, cv::arcLength(cv::Mat(contours[i]), true)*0.02, true);
if (approx.size() >= 4 && approx.size() <= 6)
Rect boundRect = boundingRect( Mat(approx) );
rectangle( dst, boundRect.tl(), boundRect.br(), Scalar(255,255,255), 1, 8, 0 );}
Only one rectangle is detected. Can you please guide me or some link for the same.
Input image:
Output image:
I could not compile your code sample because there boundRect is declared within the if-block but rectangle drawing (trying to access boundRect) is outside of the if-block, so I adjusted your code:
int main(int argc, char* argv[])
{
cv::Mat src = cv::imread("C:/StackOverflow/Input/rectangles.png");
cv::Mat dst = src.clone();
cv::Mat gray;
cv::cvtColor(src, gray, CV_BGR2GRAY);
// ADDED: missing declaration of mu and sigma
cv::Scalar mu, sigma;
meanStdDev(gray, mu, sigma);
cv::Mat bw;
cv::Canny(gray, bw, mu.val[0] - sigma.val[0], mu.val[0] + sigma.val[0]);
// ADDED: displaying the canny output
cv::imshow("canny", bw);
std::vector<std::vector<cv::Point> > contours;
cv::findContours(bw.clone(), contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
std::vector<cv::Point> approx;
for (int i = 0; i < contours.size(); i++){
cv::approxPolyDP(cv::Mat(contours[i]), approx, cv::arcLength(cv::Mat(contours[i]), true)*0.02, true);
if (approx.size() >= 4 && approx.size() <= 6)
{
// ADDED: brackets around both lines belonging to the if-block
cv::Rect boundRect = cv::boundingRect(cv::Mat(approx));
cv::rectangle(dst, boundRect.tl(), boundRect.br(), cv::Scalar(255, 255, 255), 3, 8, 0);
}
}
// ADDED: displaying input and results
cv::imshow("input", src);
cv::imshow("dst", dst);
cv::imwrite("C:/StackOverflow/Output/rectangles.png", dst);
cv::waitKey(0);
return 0;
}
with your input image I do get this output:
which is probably not what you expected. See the canny output image (it is always good to have a look at intermediate results for visual debugging!), there are just too many structures in the image and contours will cover all of these, so there are some that will be approximated to polynomes with 4 to 6 elements.
Instead you'll have to become a bit smarter. You could try to extract straight lines with cv::HoughLinesP and connect those lines. Or you could try to segment the image first by finding white areas (if your rectangles are always white).
int main(int argc, char* argv[])
{
cv::Mat src = cv::imread("C:/StackOverflow/Input/rectangles.png");
cv::Mat dst = src.clone();
cv::Mat gray;
cv::cvtColor(src, gray, CV_BGR2GRAY);
cv::Mat mask;
// find "white" pixel
cv::inRange(src, cv::Scalar(230, 230, 230), cv::Scalar(255, 255, 255), mask);
cv::imshow("mask", mask);
std::vector<std::vector<cv::Point> > contours;
cv::findContours(mask, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
std::vector<cv::Point> approx;
for (int i = 0; i < contours.size(); i++){
cv::approxPolyDP(cv::Mat(contours[i]), approx, cv::arcLength(cv::Mat(contours[i]), true)*0.02, true);
if (approx.size() >= 4 && approx.size() <= 6)
{
cv::Rect boundRect = cv::boundingRect(cv::Mat(approx));
cv::rectangle(dst, boundRect.tl(), boundRect.br(), cv::Scalar(255, 255, 255), 1, 8, 0);
}
}
cv::imshow("input", src);
cv::imshow("dst", dst);
cv::imwrite("C:/StackOverflow/Output/rectangles2.png", dst);
cv::waitKey(0);
return 0;
}
gives this result:
As you can see, there are other bright regions near white, too. The polynom approximation does not help much, too.
In general, it's easier to segment a color (even white) in HSV space. With appropriate thresholds:
inRange(hsv, Scalar(0, 0, 220), Scalar(180, 30, 255), mask);
where we don't care about the Hue, and keep only low Saturation and high Value, I get:
Then you can easily find connected components, and discard blobs smaller than a threshold th_blob_size. Resulting rectangles are (in green):
You can eventually apply other filtering stage to account for more difficult situations, but for this image removing small blobs is enough. Please post other images if you need something more robust in general.
Code:
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main(int argc, char** argv)
{
Mat3b img = imread("path_to_image");
int th_blob_size = 100;
Mat3b hsv;
cvtColor(img, hsv, COLOR_BGR2HSV);
Mat1b mask;
inRange(hsv, Scalar(0, 0, 220), Scalar(180, 30, 255), mask);
vector<vector<Point>> contours;
findContours(mask.clone(), contours, RETR_EXTERNAL, CHAIN_APPROX_NONE);
Mat3b res = img.clone();
for (int i = 0; i < contours.size(); ++i)
{
// Remove small blobs
if (contours[i].size() < th_blob_size)
{
continue;
}
Rect box = boundingRect(contours[i]);
rectangle(res, box, Scalar(0,255,0), 1);
}
imshow("Result", res);
waitKey();
return 0;
}
Are you sure you are only finding one contour or are you only drawing one contour? It doesn't look like you are looping in the drawing routine so you will only ever draw the first one that is found.
I have a blog, long since dead, that may provide you some good direction on this: http://workingwithcomputervision.blogspot.co.uk/2012/09/game-player-step-2-finding-game-board.html
Should the link die I believe this is the most relevant part of the article which relates to drawing contours:
//Draw contours
for (int i = 0; i < contours.size(); i++) {
Scalar color = Scalar(0, 255, 0);
drawContours(drawing, contours, i, color, 2, 8, hierarchy, 0, Point());
}
I notice you are using bounding rectangles for the drawing. Here is an alternative drawing routine, again from the above link, that does this:
Rect bounds;
Mat drawing = Mat::zeros(purpleOnly.size(), CV_8UC3);
int j = 0;
for (int i = 0; i < contours.size(); i++) {
if (arcLength(contours[i], true) > 500){
Rect temp = boundingRect(contours[i]);
rectangle(drawing, temp, Scalar(255, 0, 0), 2, 8);
if (j == 0) {
bounds = temp;
} else {
bounds = bounds | temp;
}
j++;
}
}
Note that I also do some checks on the size of the contour to filter out noise.

How to filter contours by bounding rect size using OpenCV and C++?

I try to detect license plate from image using OpenCV and C++. I can find the contours of license plate. But I want to drop only license plate. I have a idea to filter contours by bounding rect size.
Here is my code:
#include <opencv\cv.h>
#include <opencv\highgui.h>
#include <opencv\ml.h>
#include <opencv\cxcore.h>
#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include <stdio.h>
#include <stdlib.h>
#include<iostream>
using namespace cv;
using namespace std;
cv::Mat _img;
cv::Mat _imgGray;
int main()
{
_img = cv::imread("bs9.jpg");
if (_img.empty()) {
std::cout << "error: image not read from file\n\n";
return(0);
}
cv::Mat src;
medianBlur(_img, src, 9);
// chuyển ảnh gốc sang ảnh xám
cv::cvtColor(src, _imgGray, CV_BGR2GRAY);
cv::Mat _imgGray2;
medianBlur(_imgGray, _imgGray2, 7);
blur(_imgGray2, _imgGray2, Size(3, 3));
//Canny
cv::Mat edges;
//dalation
//cv::Canny(_imgGray, edges, 100, 250);
cv::Canny(_imgGray2, edges, 100, 200, 3);
//contour
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
//
//vector<Rect> boundRect(contours.size());
//CvMemStorage* stor = cvCreateMemStorage(1000);
findContours(edges, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));
// vẽ đường bao các cạnh
Mat drawing = Mat::zeros(edges.size(), CV_8UC3);
for (int i = 0; i < contours.size(); i++)
{
Scalar color = Scalar(0,255,0);
drawContours(drawing, contours, i, color, 2, 8, hierarchy, 0, Point());
}
//filter contour
????
/// show image
cv::imshow("Goc", _img); // show ảnh gốc
//
//cv::namedWindow("Anh xam", CV_WINDOW_AUTOSIZE);
cv::imshow("Xam", _imgGray); // show ảnh xám
cv::imshow("edges", edges); // show ảnh Canny
cv::imshow("contours", drawing);
cv::waitKey(0);
return(0);
}
You can use boundingRect(or boundingBox in some versions) Function in opencv to extract the bounding box of a contour.
int w_threshold = 100;
int h_threshold = 100;
vector<int> selected;
for (int i = 0; i < contours.size(); i++)
{
Scalar color = Scalar(0, 255, 0);
Rect R = boundingRect(contours[i]);
// filter contours according to their bounding box
if (R.width > w_threshold && R.height > h_threshold)
{
selected.push_back(i);
drawContours(drawing, contours, i, color, 2, 8, hierarchy, 0, Point());
}
}
//filter contour
/// show image
cv::imshow("Goc", _img); // show ảnh gốc
for (size_t i = 0; i < selected.size(); i++)
{
rectangle(_img, boundingRect(contours[selected[i]]), Scalar(0, 0, 255), 5);
}
cv::imshow("license candidates", _img); // show ảnh xám
and this was my output:
you can also use cvBlobLibs library. It has easy functions to manipulate blobs like what you want to do.
Here is my update code. I want to filter contours with ratio of width and height.
#include <opencv\cv.h>
#include <opencv\highgui.h>
#include <opencv\ml.h>
#include <opencv\cxcore.h>
#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include <opencv2\imgcodecs.hpp>
#include <stdio.h>
#include <stdlib.h>
#include<iostream>
using namespace cv;
using namespace std;
//khai báo biến
cv::Mat _img; // ảnh gốc
cv::Mat _imgGray; // ảnh xám
//hàm main
int main()
{
_img = cv::imread("bs9.jpg");
if (_img.empty()) {
std::cout << "error: image not read from file\n\n";
return(0);
}
cv::Mat src;
medianBlur(_img, src, 9);
// chuyển ảnh gốc sang ảnh xám
cv::cvtColor(src, _imgGray, CV_BGR2GRAY);
cv::Mat _imgGray2;
medianBlur(_imgGray, _imgGray2, 7);
blur(_imgGray2, _imgGray2, Size(3, 3));
//Canny
cv::Mat edges;
//dalation
//cv::Canny(_imgGray, edges, 100, 250);
cv::Canny(_imgGray2, edges, 100, 200, 3);
//contour
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
findContours(edges, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));
//mới
vector<vector<Point> > contours_poly(contours.size());
vector<Rect> boundRect(contours.size());
vector<Point2f> ContArea(contours.size());
for (int i = 0; i < contours.size(); i++)
{
approxPolyDP(Mat(contours[i]), contours_poly[i], 3, true);
boundRect[i] = boundingRect(Mat(contours_poly[i]));
}
//mới
// vẽ đường bao các cạnh
Mat drawing = Mat::zeros(edges.size(), CV_8UC3);
//vector<Rect> boundRect(contours.size());
for (int i = 0; i < contours.size(); i++)
{
Scalar color = Scalar(0,255,0);
//drawContours(drawing, contours, i, color, 2, 8, hierarchy, 0, Point());
drawContours(drawing, contours_poly, (int)i, color, 1, 8, vector<Vec4i>(), 0, Point());
rectangle(drawing, boundRect[i].tl(), boundRect[i].br(), color, 2, 8, 0);
}
//filter contour
/// show image
cv::imshow("Goc", _img); // show ảnh gốc
//
cv::imshow("Xam", _imgGray); // show ảnh xám
cv::imshow("edges", edges); // show ảnh Canny
cv::imshow("contours", drawing);
cv::waitKey(0);
return(0);
}

OpenCV Skin Detection

I've been doing some skin detection but can't get a smooth one. The image below contains the input (left) and output (right) using the code also attached below. Now, the desired output should have been the bottom most image (the one that is smooth on the edges and doesn't have holes within). How do I achieve this output? A sample code on where to start would be of great help.
Input (left) and Incorrect output (right):
Desired output:
Code to generate the Incorect output:
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace cv;
int main(){
Mat src = imread("qq.jpg");
if (src.empty())
return -1;
blur( src, src, Size(3,3) );
Mat hsv;
cvtColor(src, hsv, CV_BGR2HSV);
Mat bw;
inRange(hsv, Scalar(0, 10, 60), Scalar(20, 150, 255), bw);
imshow("src", src);
imshow("dst", bw);
waitKey(0);
return 0;
}
Modified Code (after Astor's suggestion):
(the problem now is: how do you smoothen the output?)
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace cv;
int findBiggestContour(vector<vector<Point> >);
int main(){
Mat src = imread("qq.jpg");
if (src.empty())
return -1;
blur( src, src, Size(3,3) );
Mat hsv;
cvtColor(src, hsv, CV_BGR2HSV);
Mat bw;
inRange(hsv, Scalar(0, 10, 60), Scalar(20, 150, 255), bw);
imshow("src", src);
imshow("dst", bw);
Mat canny_output;
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
findContours( bw, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );
int s = findBiggestContour(contours);
Mat drawing = Mat::zeros( src.size(), CV_8UC1 );
drawContours( drawing, contours, s, Scalar(255), -1, 8, hierarchy, 0, Point() );
imshow("drw", drawing);
waitKey(0);
return 0;
}
int findBiggestContour(vector<vector<Point> > contours){
int indexOfBiggestContour = -1;
int sizeOfBiggestContour = 0;
for (int i = 0; i < contours.size(); i++){
if(contours[i].size() > sizeOfBiggestContour){
sizeOfBiggestContour = contours[i].size();
indexOfBiggestContour = i;
}
}
return indexOfBiggestContour;
}
You should use findContours to detect the biggest contour and after this draw founded contour with fill parameter -1 using method drawContours. Here's useful link: http://docs.opencv.org/doc/tutorials/imgproc/shapedescriptors/find_contours/find_contours.html
To improve the smoothness of the output, or in other words to reduce the black holes in the detected area try performing morphological operations on the resulting image.
Following documentation explains the eroding and dilating functions in opencv.
http://docs.opencv.org/doc/tutorials/imgproc/erosion_dilatation/erosion_dilatation.html