Perform Canny Edge in HSV Image - opencv

I had converted an BGR image to HSV to detect the black circles, then how I perform Canny edge on the HSV image? I had tried but it doesn't works at all.
IplImage *capturedImg = cvLoadImage("template.jpg",1);
IplImage* imgHSV = cvCreateImage(cvGetSize(capturedImg), 8, 3);
cvCvtColor(capturedImg, imgHSV, CV_BGR2HSV);
IplImage* imgThreshed = cvCreateImage(cvGetSize(capturedImg), 8, 1);
cvInRangeS(imgHSV, cvScalar(0, 0,0), cvScalar(255, 255, 38),imgThreshed);
cvShowImage("HSV",imgThreshed);
IplImage*cannyImg2=cvCreateImage(cvGetSize(imgThreshed),8,1);
cvCanny(grayscaleImg2,cannyImg2,0,255,3);
cvShowImage("canny2",cannyImg2);
The first image is eyes detection, then I use HSV image to detect the pupil, so how can I know the position of pupils and its radius?

I believe the line:
cvCanny(grayscaleImg2, cannyImg2, 0, 255, 3);
should instead be:
cvCanny(imgThreshed, cannyImg2, 0, 255, 3);
because you want to find the contours on the thresholded mask.

Related

How to use flood fill for coloring a wall on Video Camera using OpenCV?

I need to fill wall paint with real time video camera using flood fill, the below code results in a white layer on the image:
(void) processImage:(cv::Mat&)image
{
cv::Mat mask;
cv::Point seed(100,200);
cvtColor(image, image, cv::COLOR_RGBA2RGB);
cv::floodFill(image, mask, seed, cv::Scalar(255, 10, 20) ,0, cv::Scalar(2,2, 2), cv::Scalar(2,2, 2), 4 );
cvtColor(image, image, cv::COLOR_RGB2RGBA);
}
Can anyone help me out?
Solved!!.... Remove this conversion......
cvtColor(image, image, cv::COLOR_RGB2RGBA);
You got converted image from mask
Try this
-(void) processImage:(cv::Mat&)image
{
cv::Mat mask;
cv::Point seed(100,200);
cvtColor(image, image, cv::COLOR_RGBA2RGB);
cv::floodFill(image, mask, seed, cv::Scalar(255, 10, 20) ,0, cv::Scalar(2,2, 2), cv::Scalar(2,2, 2), 4 );
// Now you will get converted image from 'mask'
}

How to get cropped image after fisheye calibration in OpenCV

I am trying to calibrated fisheye camera in OpenCV 3.2. This is a code:
Mat newCamMat;
cameraMatrix= getOptimalNewCameraMatrix(cameraMatrix, distCoeffs, imageSize, 0, imageSize, 0); //Does not change anything
fisheye::estimateNewCameraMatrixForUndistortRectify(cameraMatrix, distCoeffs, imageSize,
Matx33d::eye(), newCamMat, 1);
fisheye::initUndistortRectifyMap(cameraMatrix, distCoeffs, Matx33d::eye(), newCamMat, imageSize,
CV_16SC2, map1, map2);
I used these flags in calibration:
fisheye::CALIB_FIX_SKEW | fisheye::CALIB_RECOMPUTE_EXTRINSIC | fisheye::CALIB_CHECK_COND
I want to get image cropped without the black areas around the usable area. For non-fisheye calibration I did it by setting alpha. For fisheye I dont know how to change it.Any suggestions?
Desired result (inside the red rectangle)
Calibration result
You can use a masked setTo to set the Alpha channel value to be transparent.
Mat img = imread("fisheye.png",-1), gray, mask;
cvtColor(img, gray, cv::COLOR_BGR2GRAY);
threshold(gray, mask, 0, 255, cv::THRESH_BINARY_INV);
cvtColor(img, img, cv::COLOR_BGR2BGRA);
img.setTo(Scalar(0,0,0,0),mask);

openCV inRange masking

I'm using Opencv 3.0 to get only the colored objects in an image. Therefore i create and use a mask.
#include <opencv2\opencv.hpp>
using namespace cv;
using namespace std;
int main()
{
namedWindow("Display", CV_WINDOW_AUTOSIZE);
namedWindow("Orignial", CV_WINDOW_AUTOSIZE);
namedWindow("Mask", CV_WINDOW_AUTOSIZE);
// First load your image
Mat mSrc = imread("IMG_0005_AUSZUG2.png", CV_LOAD_IMAGE_COLOR);
Mat mGray = Mat::zeros(mSrc.size(), mSrc.type());
cvtColor(mSrc, mGray, CV_BGR2GRAY);
// define your mask
Mat mask = Mat::zeros(mSrc.size(), mSrc.type());
// define destination image
Mat dstImg = Mat::zeros(mSrc.size(), mSrc.type());
//finding mask
inRange(mSrc, Scalar(90, 90, 90), Scalar(180, 180, 180), mask);
// combination of mask and Source image
dilate(mask, mask, Mat(), Point(-1, -1));
bitwise_not(mask, mask);
//cvtColor(mask, mask, CV_GRAY2BGR);
mSrc.copyTo(dstImg, mask);
//bitwise_and(mSrc, mSrc, dstImg, mask);
imshow("Mask", mask);
imshow("Orignial", mSrc);
imshow("Display", dstImg);
waitKey(0);
return 0;
}
As you can see the result image is not the intended one. Only the colored objects should stay, because they have a white background in the mask, but it seems that the result image is a combination of source and mask.
Anybody know how to fix this ?
Source:
Mask:
Result:
To understand your requirement- you have an image with some coloured objects in it, in a white background, and you essentially want an result image containing the same coloured objects in a black background instead.
If that's the case, inRange will not help because you've essentially kept the threshold between grey values 90 and 180, so your code will discard dark objects as well.
To ensure that you obtain a mask that is black only in the white background regions, I would suggest using the threshold function instead, as shown:
//finding mask
//inRange(mSrc, Scalar(90, 90, 90), Scalar(180, 180, 180), mask);
threshold(mGray, mask, 220, 255, THRESH_BINARY_INV);
This function will ensure that any pixel value in your greyscale image above 220 will be set to 0 in the binary mask.
To superimpose the binary mask over the source image, you should use the subtract method, as shown:
cvtColor(mask,mask,CV_GRAY2BGR);//change thresh to a 3 channel image
Mat mResult = Mat::zeros(mSrc.size(), mSrc.type());
subtract(mask,mSrc,mResult);
subtract(mask,mResult,mResult);

thresholding an image with bright zones

I am developing an app for iOS with openCV that take a picture from a monitor and extract a curve, but when the image has some bright zones after thresholding, I don't get the complete curve but some black zones
Original image
processed image after thresholding
original = [MAOpenCV cvMatGrayFromUIImage:_sourceImage];
cv::threshold(original, original, 70, 255, CV_THRESH_BINARY | CV_THRESH_OTSU);
findContours(original, contours, hierarchy,CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );
cv::Mat skel(original.size(), CV_8UC1, cv::Scalar(0));
int idx = 0;
for(; idx >= 0; idx = hierarchy[idx][0])
{
if (contours[idx].size()>250 && idx>-1){
cv::Scalar color( 255,255,255);
drawContours(skel, contours, idx, color, CV_FILLED, 8, hierarchy);
}
}
cv::threshold(skel, skel, 100, 255, CV_THRESH_BINARY_INV);
cv::erode(skel,skel,cv::Mat(),cv::Point(-1,-1),2);
So how I can process the image to extract the curve when the image have some bright zones like the example
When you have a background with an uneven illumination, you may want to apply first a White Top-Hat (or here for MatLab, and here for OpenCV).
Here is the result I got using a structuring element of type disk with radius 3.
Then, whatever thresholding method you choose will work.
Wouldn't be sufficient to use Otsu's thresholding?
Code fragment:
import cv2
image = cv2.imread('d:/so.jpg', cv2.IMREAD_GRAYSCALE)
threshold, thresholded = cv2.threshold(image, 0, 255, type=cv2.THRESH_BINARY + cv2.THRESH_OTSU)
print(threshold)
cv2.imshow('so', image);
cv2.imshow('thresholded', thresholded)
cv2.waitKey(0)

Find overlapping/complex circles with OpenCV

I want to compute the red circles radius (fig 2). I have troubles finding these circles using HoughCircles from OpenCV. As you can see in fig. 2 I can only find the little circles in center which are shown in black using HoughCircles.
original fig 2.
Since I know the center of the red circles (which are the same as the red ones), is there a way to compute simply the radius of the red circles ?
Is it also possible to have a generic way of computing radius of circles on a more complex image such as this one :
Edit : Here the interesting part of my code after obtaining fig 2 :
threshold(maskedImage, maskedImage, thresh, 255, THRESH_BINARY_INV | THRESH_OTSU);
std::vector<Vec3f> circles;
// Canny(maskedImage, maskedImage, thresh, thresh * 2, 3);
HoughCircles(maskedImage, circles, CV_HOUGH_GRADIENT, 1, src_gray.rows / 4, 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 center
circle(display, center, 3, Scalar(0, 255, 0), -1, 8, 0);
// circle outline
circle(display, center, radius, Scalar(0, 0, 255), 3, 8, 0);
}
I have tried to use play with cannyThreshold and accumulator without results. Real images are 5x biggers. Here a link for example 1 after threshold.
Thanks
You already know the smaller circles in the image(which you have drawn in black).
Prepare a mask image using these circles so the areas having smaller circles will have non-zero pixels. We'll call it mask:
In the original image, fill these circle areas in a dark color(say black). This will result in an image like your fig 2. We'll call it filled
Threshold the filled image to obtain the dark areas. We'll call it binary. You can use Otsu thresholding for this. Result will look something like this:
Take the distance transform of this binary image. Use an accurate distance estimation method for this. We'll call this dist. It'll look something like this. The colored one is just a heat map for more clarity:
Use the mask to obtain the peak regions from dist. The max value of each such region should give you the radius of the larger circle. You can also do some processing on these regions to arrive at a more reasonable value for radius rather than just picking up the max.
For selecting the regions, you can either find the contours of the mask and then extract that region from dist image, or, since you already know the smaller circles from applying hough-circle transform, prepare a mask from each of those circles and extract that region from dist image. I'm not sure if you can calculate max or other stats by giving a mask. Max will definitely work because the rest of the pixels are 0. You might be able calculate the stats of the region if you extract those pixels to another array.
Figures below show such mask and the extracted region from dist. For this I get a max around 29 which is consistent with the radius of that circle. Note that the images are not to scale.
mask for a circle, extracted region from dist
Here's the code (I'm not using hough-circles transform):
Mat im = imread(INPUT_FOLDER_PATH + string("ex1.jpg"));
Mat gray;
cvtColor(im, gray, CV_BGR2GRAY);
Mat bw;
threshold(gray, bw, 0, 255, CV_THRESH_BINARY|CV_THRESH_OTSU);
// filtering smaller circles: not using hough-circles transform here.
// you can replace this part with you hough-circles code.
vector<int> circles;
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
findContours(bw, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));
for(int idx = 0; idx >= 0; idx = hierarchy[idx][0])
{
Rect rect = boundingRect(contours[idx]);
if (abs(1.0 - ((double)rect.width/rect.height) < .1))
{
Mat mask = Mat::zeros(im.rows, im.cols, CV_8U);
drawContours(mask, contours, idx, Scalar(255, 255, 255), -1);
double area = sum(mask).val[0]/255;
double rad = (rect.width + rect.height)/4.0;
double circArea = CV_PI*rad*rad;
double dif = abs(1.0 - area/circArea);
if (dif < .5 && rad < 50 && rad > 30) // restrict the radius
{
circles.push_back(idx); // store smaller circle contours
drawContours(gray, contours, idx, Scalar(0, 0, 0), -1); // fill circles
}
}
}
threshold(gray, bw, 0, 255, CV_THRESH_BINARY_INV|CV_THRESH_OTSU);
Mat dist, distColor, color;
distanceTransform(bw, dist, CV_DIST_L2, 5);
double max;
Point maxLoc;
minMaxLoc(dist, NULL, &max);
dist.convertTo(distColor, CV_8U, 255.0/max);
applyColorMap(distColor, color, COLORMAP_JET);
imshow("", color);
waitKey();
// extract dist region corresponding to each smaller circle and find max
for(int idx = 0; idx < (int)circles.size(); idx++)
{
Mat masked;
Mat mask = Mat::zeros(im.rows, im.cols, CV_8U);
drawContours(mask, contours, circles[idx], Scalar(255, 255, 255), -1);
dist.copyTo(masked, mask);
minMaxLoc(masked, NULL, &max, NULL, &maxLoc);
circle(im, maxLoc, 4, Scalar(0, 255, 0), -1);
circle(im, maxLoc, (int)max, Scalar(0, 0, 255), 2);
cout << "rad: " << max << endl;
}
imshow("", im);
waitKey();
Results(scaled):
Hope this helps.

Resources