I try to count the number of hearts in the following image by using a canny edge detection algorithm and contours.
But after the contours I have gotten image like this and it has contoured 4 instead of 3. What kind of method I have to follow to count any number of object different shapes of deck card pack. I only need number of symbols in the middle.
Here is my c++ code
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <opencv2/core/core.hpp>
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
using namespace cv;
using namespace std;
Mat src;
Mat dst;
Mat canny_output;
//this is function for loading the image
void loadImage(char* source){
Mat tmp;
/// Load source image and convert it to gray
src = imread( source, 1 );
/// Convert image to gray and blur it
cvtColor( src, tmp, CV_RGB2GRAY );
//blur( src_gray, src_gray, Size(3,3) );
bitwise_not( tmp, src);
}
void clearImage(){
int i,j;
int r = 10;
Mat clone;
src.copyTo(clone);
for(i = 0;i < src.rows;++i){
j = 0;
clone.at<Vec3b>(i,j) = Vec3b(0,0,0);
for(j = 0;j < src.cols;++j){
if(src.at<cv::Vec3b>(i,j) == cv::Vec3b(255,255,255)){
rectangle(
clone,
cv::Point(i-r, j),
cv::Point(i+r, j+r),
cv::Scalar(255, 255, 255)
);
}
}
}
}
void detectImages(){
int thresh = 100;
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
Canny( src, canny_output, thresh, thresh*2, 3 );
/// Find contours
findContours( canny_output, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );
cout<<(hierarchy.size())<<endl;
}
//corpping and resizing the image
void corpResizeImage(){
int i,j;
Vec3b intensity;
intensity.val[0] = 0;
intensity.val[1] = 0;
intensity.val[2] = 0;
cv::Rect myROI(src.cols/6,0, 2*src.cols/3, src.rows);
Mat croppedImage = src(myROI);
Size size(300,600);
resize(croppedImage,src,size);//resize image
for(i = 0;i < src.rows;++i){
j = 0;
if((i < src.rows/25)||(i < (src.rows/25))){
for(j = 0;j < src.cols;++j){
src.at<Vec3b>(i,j)= intensity;
}
}
}
}
/** #function main */
int main( int argc, char ** argv )
{
loadImage("img/3h.png");
corpResizeImage();
detectImages();
/// Create Window
char* source_window = "Source";
namedWindow( source_window, CV_WINDOW_AUTOSIZE );
imshow( source_window, canny_output );
waitKey(0);
return(0);
}
Related
I copied the code of Harris corner detector from openCV documentation site, but i wanted to make the trackbar and its output appear in the same window so i updated the code to be
#include "stdafx.h"
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace cv;
using namespace std;
/// Global variables
Mat src, src_gray;
int thresh = 100;
int max_thresh = 255;
char* corners_window = "Corners detected";
void cornerHarris_demo( int, void* )
{
Mat dst, dst_norm, dst_norm_scaled;
dst = Mat::zeros( src.size(), CV_32FC1 );
/// Detector parameters
int blockSize = 2;
int apertureSize = 3;
double k = 0.04;
/// Detecting corners
cornerHarris( src_gray, dst, blockSize, apertureSize, k, BORDER_DEFAULT );
/// Normalizing
normalize( dst, dst_norm, 0, 255, NORM_MINMAX, CV_32FC1, Mat() );
convertScaleAbs( dst_norm, dst_norm_scaled );
/// Drawing a circle around corners
for( int j = 0; j < dst_norm.rows ; j++ )
{ for( int i = 0; i < dst_norm.cols; i++ )
{
if( (int) dst_norm.at<float>(j,i) > thresh )
{
circle( src, Point( i, j ), 5, Scalar(255,0,0), 2, 8, 0 );
}
}
}
/// Showing the result
imshow( corners_window, src);
}
/** #function main */
int main( int argc, char** argv )
{
/// Load source image and convert it to gray
char* filename = "myimage.jpg";
src_gray = imread( filename, 0);
cvtColor(src_gray,src,CV_GRAY2RGB);
/// Create a window and a trackbar
namedWindow( corners_window, CV_WINDOW_AUTOSIZE);
createTrackbar( "Threshold: ", corners_window, &thresh, max_thresh, cornerHarris_demo );
cornerHarris_demo( 0, 0 );
waitKey(0);
return(0);
}
The problem is the output window is inactive i can't open it and play with the trackbar, but i can see it from the taskbar.
This update works
#include "stdafx.h"
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace cv;
using namespace std;
/// Global variables
Mat src, src_gray;
int thresh = 200;
int max_thresh = 255;
/// Function header
void cornerHarris_demo( int, void* );
/** #function main */
int main( int argc, char** argv )
{
/// Load source image and convert it to gray
src = imread("chessboard.jpg");
cvtColor( src, src_gray, CV_BGR2GRAY );
/// Create a window and a trackbar
namedWindow( "Source image", CV_WINDOW_AUTOSIZE );
createTrackbar( "Threshold: ", "Source image", &thresh, max_thresh, cornerHarris_demo );
cornerHarris_demo( 0, 0 );
waitKey(0);
return(0);
}
/** #function cornerHarris_demo */
void cornerHarris_demo( int, void* )
{
Mat dst, dst_norm, dst_norm_scaled, temp;
src.copyTo(temp);
dst = Mat::zeros( src.size(), CV_32FC1 );
/// Detector parameters
int blockSize = 2;
int apertureSize = 3;
double k = 0.04;
/// Detecting corners
cornerHarris( src_gray, dst, blockSize, apertureSize, k, BORDER_DEFAULT );
/// Normalizing
normalize( dst, dst_norm, 0, 255, NORM_MINMAX, CV_32FC1, Mat() );
convertScaleAbs( dst_norm, dst_norm_scaled );
/// Drawing a circle around corners
for( int j = 0; j < dst_norm.rows ; j++ )
{ for( int i = 0; i < dst_norm.cols; i++ )
{
if( (int) dst_norm.at<float>(j,i) > thresh )
{
circle( temp, Point( i, j ), 5, Scalar(255,0,0), 2, 8, 0 );
}
}
}
/// Showing the result
imshow( "Source image", temp );
}
Still don't know why the first one didn't.
User,
I want to crop that Triangle on the image and show it in another window with opencv c++. I know all three Coordinates.
Can anyone help me? I did not find any answer on the Internet about "triangle cropping". Thanks!
EDIT: The Problem here is that i cannot use ROI for cropping the Triangle. I have to copy just the triangle without any background or something around. Is it possible to create my own ROI by knowing the Coordinates of the triangle [p1(302,179), p2(329,178), p3(315,205)]?
cv::Mat inputImage = cv::imread("input.png");
if (inputImage.channels() > 1)
{
cv::cvtColor(inputImage, inputImage, CV_RGB2GRAY);
}
// replace these values with your actual coordinates
// I found these by first saving your provided image, then
// using Microsoft Paint
int x0 = 242;
int y0 = 164;
int x1 = 314;
int y1 = 38;
int x2 = 387;
int y2 = 164;
// then create a line masking using these three points
cv::Mat lineMask = cv::Mat::zeros(inputImage.size(), inputImage.type());
cv::line(lineMask, cv::Point(x0, y0), cv::Point(x1, y1), cv::Scalar(255, 255, 0), 1, 8, 0);
cv::line(lineMask, cv::Point(x0, y0), cv::Point(x2, y2), cv::Scalar(255, 255, 0), 1, 8, 0);
cv::line(lineMask, cv::Point(x1, y1), cv::Point(x2, y2), cv::Scalar(255, 255, 0), 1, 8, 0);
// perform contour detection on your line mask
cv::vector<cv::vector<cv::Point>> contours;
cv::vector<cv::Vec4i> hierarchy;
cv::findContours(lineMask, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, cv::Point(0, 0));
// calculate the distance to the contour
cv::Mat raw_dist(lineMask.size(), CV_32FC1);
for (int i = 0; i < lineMask.rows; i++)
{
for (int j = 0; j < lineMask.cols; j++)
{
raw_dist.at<float>(i, j) = cv::pointPolygonTest(contours[0], cv::Point2f(j, i), true);
}
}
double minVal; double maxVal;
cv::minMaxLoc(raw_dist, &minVal, &maxVal, 0, 0, cv::Mat());
minVal = std::abs(minVal);
maxVal = std::abs(maxVal);
// depicting the distances graphically
cv::Mat mask = cv::Mat::zeros(inputImage.size(), CV_8UC1);
for (int i = 0; i < mask.rows; i++)
{
for (int j = 0; j < mask.cols; j++)
{
if (raw_dist.at<float>(i, j) < 0)
{
mask.at<uchar>(i, j) = static_cast<uchar>(0);
continue;
}
mask.at<uchar>(i, j) = static_cast<uchar>(255);
}
}
// inverse the input image
cv::Mat invInput;
cv::bitwise_not(inputImage, invInput);
// then get only the region of your triangle
cv::Mat outputImage;
invInput.copyTo(outputImage, mask);
cv::bitwise_not(outputImage, outputImage);
// display for debugging purpose
cv::imshow("inputImage", inputImage);
cv::imshow("lineMask", lineMask);
cv::imshow("mask", mask);
cv::imshow("outputImage", outputImage);
cv::waitKey();
This is your inputImage:
This is your lineMask:
This is your created binary mask:
And this is your final outputImage:
References:
OpenCV draw line
OpenCV findContours
Point Polygon Test
you can do it by using mask as shown with the code below
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
using namespace cv;
using namespace std;
int main( int, char** argv )
{
Mat src = imread( argv[1] );
Mat gray;
cvtColor(src, gray, COLOR_BGR2GRAY );
gray = gray < 127;
vector<vector<Point> > contours;
findContours(gray, contours,
RETR_EXTERNAL,
CHAIN_APPROX_SIMPLE);
for( size_t i = 0; i< contours.size(); i++ )
{
Rect rect = boundingRect(contours[i]);
Mat mask = gray(rect);
Mat srcROI = src(rect);
srcROI.setTo(Scalar(0,0,255),mask);
imshow("srcROI",srcROI);
waitKey();
}
imshow( "result", src );
waitKey(0);
return(0);
}
EDIT: according the change on the question i suggest the test code below
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
using namespace cv;
using namespace std;
int main( int, char** argv )
{
Mat src = imread("lena.jpg");
vector<Point> points;
points.push_back( Point(200,200));
points.push_back( Point(370,370));
points.push_back( Point(220,410));
Mat mask = Mat::zeros( src.size(), CV_8UC1 );
fillConvexPoly( mask, points, Scalar( 255 ));
Rect rect = boundingRect( points );
Mat roi = src( rect ).clone();
mask = mask( rect ).clone();
rect.x = rect.x - 180;
rect.y = rect.y - 180;
Mat srcROI = src( rect );
roi.copyTo( srcROI, mask );
imshow( "result", src );
waitKey(0);
return(0);
}
As you told that you know co-ordinates of the triangle, using below code you can find triangle.
Mat image = imread("imagePath");
bitwise_not(image, image);
Mat grayImage;
cv::cvtColor(image, grayImage, CV_RGB2GRAY);
cv::vector<cv::vector<cv::Point> > contours;
cv::vector<cv::Vec4i> hierarchy;
cv::findContours(grayImage, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, cv::Point(0, 0));
Mat contourMat(grayImage.size(), grayImage.type(), Scalar(255));
for(int i = 0; i < contours.size(); i++)
{
if(contours[i].data()->x == 314 && contours[i].data()->y == 37)
drawContours(contourMat, contours, i, Scalar(0), CV_FILLED, 8, hierarchy);
}
imshow("WindowName", contourMat);
Hope this will help.
I am trying to make sense of the hierarchy in the findContour function in OpenCV. I am using RETR_CCOMP to hopefully find the parent contours and whether or not they have 'children'. My find contour hierarchy vector seems to suggest there are far more parent contours then are visible in the output which makes it more difficult to use.
Is it possible to get around this problem?.
Here's my code:
#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;
Mat src_edges;
int main(int argc, char** argv)
{
src = imread("image.jpg", CV_LOAD_IMAGE_UNCHANGED);
cvtColor(src, src_gray, CV_BGR2GRAY);
blur(src_gray, src_gray, Size(3, 3));
Canny(src_gray, src_edges, 200, 120);
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
findContours(src_edges, contours, hierarchy, RETR_CCOMP, CV_CHAIN_APPROX_TC89_L1, Point(0, 0));
for (auto vec : hierarchy)
std::cout << vec << std::endl; // just to have a look at the hierarchy vector
int count = 0;
for (int i = 0; i < 5; i++){
if (hierarchy[i][3] != 0){
count++;
}
}
cout << "number of labels = " << count << endl;
Mat drawing = Mat::zeros(src_gray.size(), CV_8UC3);
for (int i = 0; i < contours.size(); i++)
{
Scalar color = Scalar(rand() & 255, rand() & 255, rand() & 255);;
drawContours(drawing, contours, i, color, 2, 8, hierarchy, 0, Point());
}
namedWindow("Contours", CV_WINDOW_AUTOSIZE);
imshow("Contours", drawing);
namedWindow("Original Image", CV_WINDOW_AUTOSIZE);
imshow("Original Image", src);
waitKey(0);
return(0);
}
Here an example image:
Here I did coding for finding the edge and their all coordinate points of the image but I need only two or three coordinate point of each quadrant in image.
using namespace cv;
using namespace std;
Mat src;
Mat src_gray;
int thresh = 172;
int max_thresh = 255;
RNG rng(12345);
void thresh_callback(int, void* );
int main( int argc, char** argv ){
src = imread("Led50.jpg",1);
cvtColor( src, src_gray, CV_BGR2GRAY );
blur( src_gray, src_gray, Size(3,3) );
char* source_window = "Source";
namedWindow( source_window, CV_WINDOW_AUTOSIZE );
imshow( source_window, src );
createTrackbar( " Canny thresh:", "Source", &thresh, max_thresh, thresh_callback );
thresh_callback( 0, 0 );
waitKey(0);
return(0);}
void thresh_callback(int, void* ){
Mat canny_output;
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
Canny( src_gray, canny_output, thresh, thresh*2, 3 );
findContours( canny_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );
for(unsigned int i=0;i<contours.size();i++){
for(unsigned int j=0;j<contours[i].size();j++)
{
cout << "Point(x,y)=" << contours[i][j].x << "," << contours[i][j].y << endl;
}}}
Source file:
Result and i get all the coordinate point:
And I need only marked coordinate point but not in exact position as well as each quadrant atleast have two points:
The above code is based on the canny and findcontours, I need few coordinates from images.
#include "highgui.hpp"
#include "imgproc.hpp"
#include <iostream>
using namespace cv;
using namespace std;
int main( int argc, char** argv ){
Mat src_gray;
src_gray = imread("EXnc1.jpg",0);
blur( src_gray, src_gray, Size(3,3) );
Mat bwimg = src_gray > 127;
vector<vector<Point> > contours;
findContours( bwimg, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE );
for(unsigned int i=0;i<contours.size();i++){
approxPolyDP(Mat(contours[i]), contours[i], 10, true);
if(i > 0)
{
cout << "Outer contour points \n";
}
else cout << "Inner contour points \n";
for(unsigned int j=0;j<contours[i].size();j++)
{
cout << "Point(x,y)=" << contours[i][j].x << "," << contours[i][j].y << endl;
circle( src_gray, contours[i][j], 3, Scalar(0, 0, 255), FILLED, LINE_AA );
}
imshow( "Result", src_gray );
waitKey(0);
}
return(0);}
output :
Inner contour points
Point(x,y)=343,148
Point(x,y)=419,160
Point(x,y)=461,208
Point(x,y)=457,276
Point(x,y)=403,322
Point(x,y)=322,322
Point(x,y)=269,262
Point(x,y)=279,190
Outer contour points
Point(x,y)=371,133
Point(x,y)=289,159
Point(x,y)=251,224
Point(x,y)=271,298
Point(x,y)=351,341
Point(x,y)=436,320
Point(x,y)=481,247
Point(x,y)=456,172
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/video/background_segm.hpp>
#include <iostream>
#include <windows.h>
using namespace cv;
using namespace std;
//initial min and max HSV filter values.
//these will be changed using trackbars
Mat src; Mat HSV; Mat roi; Mat range; Mat eroded; Mat gray;
int thresh = 100;
int max_thresh = 255;
/** #function main */
int main(int argc, char** argv)
{
createTrackbars();
VideoCapture cap(0); // open the default camera
if (!cap.isOpened()) // check if we succeeded
return -1;
namedWindow("background", 1);
int waitTime = 50;
int counter = 101;
int roiLeft = 20;
int roiTop = 50;
int roiRight = 200;
int roiBottom = 200;
Rect rRoi = Rect(roiLeft, roiTop, roiRight, roiBottom);
Mat background;
cap >> background;
background = background(rRoi);
//cvtColor(background, background, CV_BGR2HSV);
//imshow("background", background);
vector<vector<Point> > contours;
vector<vector < cv::Point >> hull(1);
vector<Vec4i> hierarchy;
vector<CvConvexityDefect> defects;
while (true)
{
cap >> src;
//Create the region of interest.
Mat iRoi = src.clone()(rRoi);
Mat iRoiSRC = src(rRoi);
//Draw a rectangle there.
rectangle(src, rRoi, Scalar(255, 128, 0), 1, 8, 0);
//imshow("roi", iRoi);
//Subtract the static background.
absdiff(iRoi, background, iRoi);
//imshow("diff", iRoi);
//Convert it to a GrayScale and threshold it.
cvtColor(iRoi, iRoi, CV_BGR2GRAY);
threshold(iRoi, gray, 15, 255, CV_THRESH_BINARY);
//Perform a closing.
Mat erodeElement = getStructuringElement(MORPH_ELLIPSE, Size(erodeSize, erodeSize));
Mat dilateElement = getStructuringElement(MORPH_ELLIPSE, Size(dilateSize, dilateSize));
for (int index = 0; index < loopAmount; index++)
{
erode(gray, gray, erodeElement);
dilate(gray, gray, dilateElement);
}
//imshow("range", gray);
//Find the contours.
findContours(gray, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));
//Pick the biggest contour.
int biggestContourIndex = 0;
int largestArea = 0;
for (int i = 0; i < contours.size(); i++)
{
if (contours[i].size() > largestArea)
{
largestArea = contours[i].size();
biggestContourIndex = i;
}
}
vector<int> hullsI;
vector<Point> hullsP;
vector<Vec4i> defects;
//Find the convex hull.
if (contours.size() > 0)
{
convexHull(contours[biggestContourIndex], hullsI, true, true);
convexHull(contours[biggestContourIndex], hullsP, true, true);
}
//Find the convexity defects.
if (contours.size() > 0)
{
if (contours[biggestContourIndex].size() > 3)
{
convexityDefects(contours[biggestContourIndex], hullsI, defects);
}
}
//Draw the biggest contour and its convex hull.
Scalar colorOne = Scalar(255, 128, 0);
Scalar colorTwo = Scalar(0, 0, 255);
if (contours.size() > 0)
{
drawContours(iRoiSRC, contours, biggestContourIndex, colorOne, 2, 8, hierarchy, 0, Point());
drawContours(iRoiSRC, hullsP, 0, colorTwo, 1, 8, vector<Vec4i>(), 0, Point());
rectangle(iRoiSRC, boundingRect(contours[biggestContourIndex]), Scalar(0, 255, 0), 1, 8, 0);
}
imshow("src", src);
if (waitKey(waitTime) >= 0) break;
}
return(0);
}
There is a rectangle in the upper left of the screen, where my hand will be recognized once I hold it there.
The error that i get appears at the first drawContours. The full error which is given to me by the console is: OpenCV Error: Assertion failed <i <0> in cv::_InputArray::getMat, file C:\buildslave64\win64_amdoc1\2_4_PackSlave-win64-vc11-shared\opencv\modules\core\src\matrix.cpp, line 963
I've been extensively searching for a solution on multiple sites, including stackoverflow but none of the solution seem to be working.
Any help would be appreciated.
I use Visual studio 2013 with OpenCV-2.4.10
converting vector<CvConvexityDefect> defects; to a point seemed to do the trick