I'm trying to use Harris Corner detection algorithm of OpenCV to find corners in an image. I want to track it across consecutive frames using Lucas-Kanade Pyramidal Optical flow.
I have this C++ code, which doesn't seem to work for some reason:
#include <stdio.h>
#include "opencv2/core/core.hpp"
#include "opencv2/calib3d/calib3d.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/contrib/contrib.hpp"
#include "opencv2/opencv.hpp"
using namespace cv;
using namespace std;
void main()
{
Mat img1, img2;
Mat disp1, disp2;
int thresh = 200;
vector<Point2f> left_corners;
vector<Point2f> right_corners;
vector<unsigned char> status;
vector<float> error;
Size s;
s.height = 400;
s.width = 400;
img1 = imread("D:\\img_l.jpg",0);
img2 = imread("D:\\img_r.jpg",0);
resize(img2, img2, s, 0, 0, INTER_CUBIC);
resize(img1, img1, s, 0, 0, INTER_CUBIC);
disp1 = Mat::zeros( img1.size(), CV_32FC1 );
disp2 = Mat::zeros( img2.size(), CV_32FC1 );
int blockSize = 2;
int apertureSize = 3;
double k = 0.04;
cornerHarris( img1, disp1, blockSize, apertureSize, k, BORDER_DEFAULT );
normalize( disp1, disp1, 0, 255, NORM_MINMAX, CV_32FC1, Mat() );
for( int j = 0; j < disp1.size().height ; j++ )
{
for( int i = 0; i < disp1.size().width; i++ )
{
if( (int) disp1.at<float>(j,i) > thresh )
{
left_corners.push_back(Point2f( j, i ));
}
}
}
right_corners.resize(left_corners.size());
calcOpticalFlowPyrLK(img1,img2,left_corners,right_corners,status,error, Size(11,11),5);
printf("Vector size : %d",left_corners.size());
waitKey(0);
}
When I run it, I get the following error message:
Microsoft Visual Studio C Runtime Library has detected a fatal error in OpenCVTest.exe.
(OpenCVTest being the name of my project)
OpenCV Error: Assertion failed ((npoints = prevPtsMat.checkVector(2, CV_32F, true)) >= 0) in unknown function, file ..\..\OpenCV-2.3.0-win-src\OpenCV-2.3.0\modules\video\src\lkpyramid.cpp, line 71
I have been trying to debug this from yesterday, but in vain. Please help.
As we can see in the source code, this error is thrown if the previous points array is in someway faulty. Exactly what makes it bad is hard to say since the documentation for checkVector is a bit sketchy. You can still look at the code to find out.
But my guess is that your left_corners variable have either the wrong type (not CV_32F) or the wrong shape.
Related
I have been trying to develop a program - written with C++ and using OpenCV -which counts the overall value of coins shown in some image.
I should note that I am new to the opencv platform.
In order to achieve this goal, as far as I understand - there has to be a use of the Hough transform to detect the ratio of the coins. I found this code example on the OpenCV site, but I can't put a value for the coins.
Here is what I have done so far.
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>
using namespace std;
using namespace cv;
namespace
{
const std::string windowName = "Coins detection";
const std::string cannyThresholdTrackbarName = "Canny threshold";
const std::string accumulatorThresholdTrackbarName = "Accumulator Threshold";
const int cannyThresholdInitialValue = 41;
const int accumulatorThresholdInitialValue = 87;
const int maxAccumulatorThreshold = 200;
const int maxCannyThreshold = 255;
void HoughDetection(const Mat& src_gray, const Mat& src_display, int cannyThreshold, int accumulatorThreshold)
{
std::vector<Vec3f> circles;
HoughCircles( src_gray, circles, HOUGH_GRADIENT, 1, src_gray.rows/8, cannyThreshold, accumulatorThreshold, 0, 0 );
Mat display = src_display.clone();
for( size_t i = 0; i < circles.size(); i++)
{
Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
int radius = cvRound(circles[i][2]);
circle( display, center, 3, Scalar(0,255,0), -1, 8, 0 );
circle( display, center, radius, Scalar(0,0,255), 3, 8, 0 );
}
imshow( windowName, display);
}
}
int main(int argc, char** argv)
{
Mat src, src_gray;
String imageName("c:\\moedas.jpg");
if (argc > 1)
{
imageName = argv[1];
}
src = imread( imageName, IMREAD_COLOR );
if( src.empty() )
{
std::cerr<<"Invalid input image\n";
return -1;
}
cvtColor( src, src_gray, COLOR_BGR2GRAY );
GaussianBlur( src_gray, src_gray, Size(9, 9), 2, 2 );
int cannyThreshold = cannyThresholdInitialValue;
int accumulatorThreshold = accumulatorThresholdInitialValue;
namedWindow( windowName, WINDOW_AUTOSIZE );
createTrackbar(cannyThresholdTrackbarName, windowName, &cannyThreshold,maxCannyThreshold);
createTrackbar(accumulatorThresholdTrackbarName, windowName, &accumulatorThreshold, maxAccumulatorThreshold);
char key = 0;
while(key != 'q' && key != 'Q')
{
cannyThreshold = std::max(cannyThreshold, 1);
accumulatorThreshold = std::max(accumulatorThreshold, 1);
HoughDetection(src_gray, src, cannyThreshold, accumulatorThreshold);
key = (char)waitKey(10);
}
return 0;
}
The code you have so far only segments circle shapes in an input image. This is just the first step to count the coins. There are many ways to perform that task, ranging from simple contour counting techniques to complicated deep learning, and the explanation of such techniques is too broad and large in scope to put efficiently and concisely in an SO answer. However, here are some coin detectors/counter implementations/tutorials that you can check:
Implementation 1 in Python. This is the best of the list, although the code file is larger than yours, not too hard to port to C++. It has the best detection/counting performance but deals with Neural Networks, specifically, a Multilayer Perceptron.
Implementation 2 in Python. This is a very small code file, nearly as large as yours and has no idiomatic Python code, porting it to C++ is a no brainer, you should start here. This implementation uses mere contour counting with the aid of the Canny edge detector.
Tutorial 1 in C++. A simple tutorial in C++, but only serves introductory purposes, the implementations listed above are the real thing.
I want to do three-channel image filtering with the help of the C++ OpenCV library. I want to do it with kernels of 3x3 matrix size, each of which is of different value. To do this, I first divided the RGB image into three channels: red, green and blue. Then I defined different kernel matrices for these three channels. Then, after processing them with the help of the filter2d function, the code threw an exception:
Unhandled exception at 0x00007FFAA150A388 in opencvTry.exe: Microsoft
C++ exception: cv::Exception at memory location 0x0000002D4CAF9660.
occurred
What is the reason I can't do it in the code below?
#include "opencv2/objdetect/objdetect.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <typeinfo>
#include <stdlib.h>
using namespace cv;
using namespace std;
int main()
{
Mat src = imread("path\\color_palette.png", IMREAD_COLOR); //load image
int blue_array[159][318];
int green_array[159][318];
int red_array[159][318];
for (int i = 0; i < src.rows; i++) {
for (int j = 0; j < src.cols; j++) {
int a = int(src.at<Vec3b>(i, j).val[0]);
blue_array[i][j] = a;
//cout << blue_array[i][j] << ' ' ;
int b = int(src.at<Vec3b>(i, j).val[1]);
green_array[i][j] = b;
int c = int(src.at<Vec3b>(i, j).val[2]);
red_array[i][j] = c;
}
}
cv::Mat blue_array_mat(159, 318, CV_32S, blue_array);
cv::Mat green_array_mat(159, 318, CV_32S, green_array);
cv::Mat red_array_mat(159, 318, CV_32S, red_array);
float kernelForBlueData[9] = { 1,0,1, 2,0,-2, 1,0,-1};
cv::Mat kernelForBlue(3, 3, CV_32F, kernelForBlueData);
float kernelForGreenData[9] = { 1./16, 2./16, 1./16, 2./16, 4./16,2./16, 1./16, 2./16, 1./16 };
cv::Mat kernelForGreen(3, 3, CV_32F, kernelForGreenData);
float kernelForRedData[9] = { 1./9,1./9, 1./9, 1./9, 1./9,1./9, 1./9, 1./9,1./9 };
cv::Mat kernelForRed(3, 3, CV_32F, kernelForRedData);
//cv::filter2D(blue_array_mat, blue_array_mat, -1, kernelForBlue, Point(-1, -1), 5.0, BORDER_REPLICATE);
filter2D(blue_array_mat, blue_array_mat, 0, kernelForBlue);
imshow("filter", blue_array_mat);
waitKey(0);
return 0;
}
You’re using a constructor for cv::Mat that expects a pointer to data (e.g. int*) but you put an int** into it. This is the reason for the crash, I presume.
Why not create the cv::Mat first and then directly write data into it?
Note the OpenCV has a function that does this for you:
cv::Mat chans[3];
cv::split(src, chans);
//...
cv::filter2D(chans[2], chans[2], 0, kernelForBlue);
Cross post here
I note the function FlannBasedMatcher::match have a parameter mask, so I give a try with following code:
#include<opencv.hpp>
#include "opencv2/core/core.hpp"
#include "opencv2/features2d/features2d.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/calib3d/calib3d.hpp"
#include "opencv2/nonfree/nonfree.hpp"
using namespace cv;
using namespace std;
int main() {
Mat rightImg = imread("right.jpg", 0);
Mat leanImg = imread("lean.jpg", 0);
if (!rightImg.data || !leanImg.data) {
cout << "Fail to read your image. Please check your path.\n";
return -1;
}
resize(leanImg, leanImg, rightImg.size());
int minHessian = 400;
SurfFeatureDetector detector(minHessian);
vector<KeyPoint> keypoints_right, keypoints_lean;
detector.detect(rightImg, keypoints_right);
detector.detect(leanImg, keypoints_lean);
Mat med_right, med_lean;
drawKeypoints(rightImg, keypoints_right, med_right);
drawKeypoints(leanImg, keypoints_lean, med_lean);
SurfDescriptorExtractor extractor;
Mat descriptors_right, descriptors_lean;
extractor.compute(rightImg, keypoints_right, descriptors_right);
extractor.compute(leanImg, keypoints_lean, descriptors_lean);
FlannBasedMatcher matcher;
vector< DMatch > matches;
Mat mask(descriptors_right.rows, descriptors_lean.rows, CV_8UC1, Scalar(0));
Mat target(rightImg.size(), CV_8UC1, Scalar(255));
ellipse(target, Point(rightImg.cols / 2, rightImg.rows / 2), Size(rightImg.cols / 2, rightImg.rows / 2), 0, 0, 360, Scalar(0), CV_FILLED);
for (int i = 0; i < mask.rows; i++) {
uchar* pixrow = mask.ptr<uchar>(i);
for (int j = 0; j < mask.cols; j++) {
if (target.at<uchar>(keypoints_right[i].pt) == 255)
pixrow[j] = 255;
}
}
matcher.match(descriptors_right, descriptors_lean, matches/*, mask*/);//use it or not to test
Mat img_matches;
drawMatches(rightImg, keypoints_right, leanImg, keypoints_lean,
matches, img_matches, Scalar::all(-1), Scalar::all(-1),
vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);
return 0;
}
And this is my right.jpg and lean.jpg. I don't care those points in the center of right.jpg. So I make a mask for it. But I note I will get a same result totally whether I use the mask in the function FlannBasedMatcher::match. You can use the mask or not to reproduce it. Do I have missed something or the OpenCV have a bug in my 2.4.13? Can anyone tell me how to use the mask in the FlannBasedMatcher::match? I think it is a usefull parameter..
From the docs: "FlannBasedMatcher does not support masking permissible matches of descriptor sets because flann::Index does not support this." See the DescriptorMatcher::isMaskSupported method for a way to test if the matcher supports masking.
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);
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.