I have two images from the same camera position. The difference between them is that one was taken with orthographic and the other was taken with perspective projection.
Here is the two image:
When I run the findContour OpenCV method on them the result is the follwing:
Why OpenCV doesn't find a closed outer contour curve for the perspective one?
I tried both CV_RETR_TREE and CV_RETR_EXTERNAL flags with the combination of CV_CHAIN_APPROX_SIMPLE and CV_CHAIN_APPROX_NONE flags.
Here is the documentation and sample code (which I am using) for the findContour method.
Actually I can't reproduce your problem. Try with this code:
#include <opencv2\opencv.hpp>
#include <vector>
using namespace std;
using namespace cv;
int main()
{
RNG rng(1234);
Mat3b img = imread("path_to_image");
Mat1b gray;
cvtColor(img, gray, COLOR_BGR2GRAY);
Mat1b bw = ~gray;
vector<vector<Point>> contours;
findContours(bw, contours, RETR_LIST, CHAIN_APPROX_SIMPLE);
for (int i = 0; i < contours.size(); ++i)
{
Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
drawContours(img, contours, i, color, 2);
}
imshow("Result", img);
waitKey();
return 0;
}
Result:
Related
From the following image, how could I find the result image?
The images shown here are threshold images. I have tried using morphological operators but they even remove the blob I want. How could I solve this problem?
Any hints?
Following is the result image I am interested to get/find:
import cv2
diff = cv2.imread('Image.png',0)
ret, thresh = cv2.threshold(diff, 12.5, 255, cv2.THRESH_BINARY)
thresh = cv2.dilate(thresh, None, iterations = 1)
cv2.imshow('img', thresh) # This is the first picture I have shown
cv2.waitKey(0)
You are most of the way there, all you need to do now is find the blobs, add some contours and find the biggest one. Easy! below is the code in C++, ill leave it up to you to work out how to convert it to Python:
cv::Mat mat = imread("g0cVU.png");
Mat origImage = mat;
Mat canny_output = mat;
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
cv::Mat greyMat, colorMat;
cv::cvtColor(mat, greyMat, CV_BGR2GRAY);
int thresh = 100;
RNG rng(12345);
///// Detect edges using canny
Canny(greyMat, canny_output, thresh, thresh * 2, 3);
/// Find contours
findContours(canny_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));
int largest_area = 0;
int largest_contour_index = 0;
Rect bounding_rect;
/// 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());
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
}
}
rectangle(origImage, bounding_rect, Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)),2);
/// Show in a window
namedWindow("Contours", CV_WINDOW_AUTOSIZE);
imshow("Contours", drawing);
cv::namedWindow("img");
cv::imshow("mat", mat);
cv::imshow("mat", origImage);
cv::imshow("mat123", drawing);
cv::waitKey(0);
Which gives this results:
You can see in the bottom image the largest contor has a brown rectangle drawn around it.
o and obviously once you have the largest blob (or whatever blob you deem "the correct one") you can just set everything else to black which is fairly straightforward.
This is a picture above. I am using opencv to process it and I have tried to use Hough Transform, but failed. Also, I found that it is so hard to set relative parameters in Hough Transform.
The codes are as following:
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main()
{
Mat srcImg = imread("srccenter.bmp");
Mat greyImg;
cvtColor(srcImg, greyImg, COLOR_BGR2GRAY);
std::vector<cv::Vec3f> circles;
/// Apply the Hough Transform to find the circles
HoughCircles(greyImg, circles, CV_HOUGH_GRADIENT, 1, 10, 100, 20, 0, 0);
/// Draw the circles detected
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(srcImg, center, 3, Scalar(0, 255, 255), -1);
circle(srcImg, center, radius, Scalar(0, 255, 0), 1);
}
namedWindow("srcImg", WINDOW_NORMAL);
imshow("srcImg", srcImg);
waitKey(0);
return 0;
}
But the result is I can not detect any circle.
How I can detect the inner circle?
Do you have any good ideas?
You need to change min_dist parameter to zero. This parameter is for minimum distance between detected centers. in your case, centers of the circles are so near.
And Also, you must change param_1, the parameter of the Canny edge detector.
How to add Scalar to Mat only where mask>0?
this code don't work as expected, area where mask>0 is img.value+scalar but where mask=0 us 0, but I expected img.value.
add(image,Scalar(0,0,80),dst, mask);
code that work as I expect is
Mat dst;
image.copyTo(dst,mask);
add(dst,Scalar(0,0,80),dst, mask);
dst.copyTo(image,mask);
dst= image;
but it's not very clear, is there any simpler variant?
Since your dst image is uninitialized, the values outside the mask are set to 0.
You get the expected behavior if you use as destination an initialized matrix. It can be your source matrix;
#include <opencv2\opencv.hpp>
using namespace cv;
int main()
{
// Initial image
Mat3b image(10, 10, Vec3b(0,2,0));
// Mask
Mat1b mask(10,10, uchar(0));
rectangle(mask, Rect(0,0,3,4), Scalar(255), CV_FILLED);
add(image, Scalar(0, 0, 3), image, mask);
return 0;
}
Or if you need the source matrix to remain unchanged, you can simply clone the source image to the destination image before the add, like:
#include <opencv2\opencv.hpp>
using namespace cv;
int main()
{
// Initial image
Mat3b image(10, 10, Vec3b(0,2,0));
// Mask
Mat1b mask(10,10, uchar(0));
rectangle(mask, Rect(0,0,3,4), Scalar(255), CV_FILLED);
Mat3b dst = image.clone();
add(image, Scalar(0, 0, 3), dst, mask);
return 0;
}
can anyone help me how to count the number of non directional edge using opencv cannyedge detection? I have a cannyEdge image from opencv and I would like to have an histogram based on edge directions and there by i can count he number of directional and non directional edges.
I think you are confusing edge detection with gradient detection. Canny provides an edge map based on the gradient magnitude (normally using a Sobel operator, but it can use others) because Canny only returns the thresholded gradient magnitude information it cannot provide you with the orientation information.
EDIT : I should clarify that the Canny algorithm does use gradient orientation for the non-maximum suppression step. However, the OpenCV implementation of Canny hides this orientation information from you, and only returns an edge magnitude map.
The basic algorithm to get magnitude and orientation of the gradient is as follows:
Compute Sobel in the X direction (Sx).
Compute Sobel in the Y direction (Sy).
Compute the gradient magnitude sqrt(Sx*Sx + Sy*Sy).
Compute the gradient orientation with arctan(Sy / Sx).
This algorithm can be implemented using the following OpenCV functions: Sobel, magnitude, and phase.
Below is a sample that computes the gradient magnitude and phase as well as shows a coarse color mapping of the gradient orientations:
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
#include <vector>
using namespace cv;
using namespace std;
Mat mat2gray(const cv::Mat& src)
{
Mat dst;
normalize(src, dst, 0.0, 255.0, cv::NORM_MINMAX, CV_8U);
return dst;
}
Mat orientationMap(const cv::Mat& mag, const cv::Mat& ori, double thresh = 1.0)
{
Mat oriMap = Mat::zeros(ori.size(), CV_8UC3);
Vec3b red(0, 0, 255);
Vec3b cyan(255, 255, 0);
Vec3b green(0, 255, 0);
Vec3b yellow(0, 255, 255);
for(int i = 0; i < mag.rows*mag.cols; i++)
{
float* magPixel = reinterpret_cast<float*>(mag.data + i*sizeof(float));
if(*magPixel > thresh)
{
float* oriPixel = reinterpret_cast<float*>(ori.data + i*sizeof(float));
Vec3b* mapPixel = reinterpret_cast<Vec3b*>(oriMap.data + i*3*sizeof(char));
if(*oriPixel < 90.0)
*mapPixel = red;
else if(*oriPixel >= 90.0 && *oriPixel < 180.0)
*mapPixel = cyan;
else if(*oriPixel >= 180.0 && *oriPixel < 270.0)
*mapPixel = green;
else if(*oriPixel >= 270.0 && *oriPixel < 360.0)
*mapPixel = yellow;
}
}
return oriMap;
}
int main(int argc, char* argv[])
{
Mat image = Mat::zeros(Size(320, 240), CV_8UC1);
circle(image, Point(160, 120), 80, Scalar(255, 255, 255), -1, CV_AA);
imshow("original", image);
Mat Sx;
Sobel(image, Sx, CV_32F, 1, 0, 3);
Mat Sy;
Sobel(image, Sy, CV_32F, 0, 1, 3);
Mat mag, ori;
magnitude(Sx, Sy, mag);
phase(Sx, Sy, ori, true);
Mat oriMap = orientationMap(mag, ori, 1.0);
imshow("magnitude", mat2gray(mag));
imshow("orientation", mat2gray(ori));
imshow("orientation map", oriMap);
waitKey();
return 0;
}
Using a circle image:
This results in the following magnitude and orientation images:
Finally, here is the gradient orientation map:
UPDATE : Abid actually asked a great question in the comments "what is meant by orientation here?", which I thought needed some further discussion. I am assuming that the phase function doesn't switch coordinate frames from the normal image processing standpoint of positive y-axis is down, and positive x-axis is right. Given this assumption that leads to following image showing the gradient orientation vectors around the circle:
This can be difficult to get used to since the axes are flipped from what we are normally used to in math class... So, gradient orientation is the angle made by the normal vector to the gradient surface in the direction of increasing change.
Hope you found that helpful!
I am trying to detect solid circles using opencv. The example code from the opencv documentation seems like it cannot detect solid white. How would I modify that code to work for solid white circles? Can you explain why it does not work for solid white circles?
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
using namespace cv;
/** #function main */
int main(int argc, char** argv)
{
Mat src, src_gray;
/// Read the image
src = imread( argv[1], 1 );
if( !src.data )
{ return -1; }
/// Convert it to gray
cvtColor( src, src_gray, CV_BGR2GRAY );
/// Reduce the noise so we avoid false circle detection
GaussianBlur( src_gray, src_gray, Size(9, 9), 2, 2 );
vector<Vec3f> circles;
/// Apply the Hough Transform to find the circles
HoughCircles( src_gray, circles, CV_HOUGH_GRADIENT, 1, src_gray.rows/8, 200, 100, 0, 0 );
/// Draw the circles detected
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 center
circle( src, center, 3, Scalar(0,255,0), -1, 8, 0 );
// circle outline
circle( src, center, radius, Scalar(0,0,255), 3, 8, 0 );
}
/// Show your results
namedWindow( "Hough Circle Transform Demo", CV_WINDOW_AUTOSIZE );
imshow( "Hough Circle Transform Demo", src );
waitKey(0);
return 0;
}
I would post images, but I don't have enough stack overflow street cred yet. Sorry!
You should extract the edges first. This is what the Hough Transform detects. Add a cvCanny transform before HoughCircles.