how to detect circle in image with openCV? - c

I want to detect circles in the image.this is the code i tried for detecting number of circles in this image:
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <stdio.h>
/** #function main */
int main(int argc, char** argv)
{
//load image from directory
IplImage* gray = cvLoadImage("comb.png",0);
// IplImage* gray = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, 1);
CvMemStorage* storage = cvCreateMemStorage(0);
//covert to grayscale
cvCvtColor(gray, gray, CV_RGB2GRAY);
// This is done so as to prevent a lot of false circles from being detected
cvSmooth(gray, gray, CV_GAUSSIAN, 7, 7);
IplImage* canny = cvCreateImage(cvGetSize(gray),IPL_DEPTH_8U,1);
//IplImage* rgbcanny = cvCreateImage(cvGetSize(gray),IPL_DEPTH_8U,3);
cvCanny(gray, canny, 10, 20, 3);
//detect circles
CvSeq* circles = cvHoughCircles(gray, storage, CV_HOUGH_GRADIENT, 1, gray->width/10);
if(circles->total>0)
printf("circles found: %d\n",circles->total);
else
printf("circles not found");
return 0;
}
but the following error occurs :-
OpenCV Error: Assertion failed (dst.data == dst0.data) in cvCvtColor, file /OpenCV/OpenCV-2.4.3/modules/imgproc/src/color.cpp, line 3811
terminate called after throwing an instance of 'cv::Exception'
what(): /OpenCV/OpenCV-2.4.3/modules/imgproc/src/color.cpp:3811: error: (-215) dst.data == dst0.data in function cvCvtColor
please tell me what is wrong with the program.i am using ubuntu linux.

You open gray as a gray image (cvLoadImage("comb.png",0), with the "0" meaning "grayscale"). Then you try to convert this gray frame from RGB to Gray, and of course this cannot work since your image is already gray.
Simply try to comment out the following line:
//covert to grayscale
cvCvtColor(gray, gray, CV_RGB2GRAY);
By the way, you should use
IplImage* gray = cvLoadImage("comb.png", CV_LOAD_IMAGE_GRAYSCALE);
instead of
IplImage* gray = cvLoadImage("comb.png", 0);
That is clearer.

Related

c printing more pages with cairo and cups

I need, in C in under a linux environment, to print documents with an image as a background.
I found an example which use Cairo vector graphics library to author a PostScript, and then sends it that off to CUPS for printing.
I modified the initial source code to integrate it with a background image (background-img.png) .
The text to be printed is more than one page, I would like to know how can I print on multiple pages keeping the same image as background and changing only the foreground text ?
How can I resize the background image to match the size of an A4 page ?
Here is the code used as a starting point :
// compile with:
// gcc -Wall -o cairo_print_png cairo_print_png.c `pkg-config --cflags --libs cairo` `cups-config --cflags --libs`
#include <stdio.h>
#include <cairo.h>
#include <cairo-ps.h>
#include <cups/cups.h>
// A4 width, height in points, from GhostView manual:
// http://www.gnu.org/software/gv/manual/html_node/Paper-Keywords-and-paper-size-in-points.html
#define WIDTH 595
#define HEIGHT 842
int main(int argc, char** argv) {
int widthPng, heightPng;
if (argc!= 2){
fprintf (stderr, "usage: %s word\n", argv[0]);
return 1;
}
// setup
char* tmpfilename = tempnam(NULL,NULL);
cairo_surface_t* surface = cairo_ps_surface_create(tmpfilename,
WIDTH,
HEIGHT);
cairo_t *context = cairo_create(surface);
// draw some text
cairo_select_font_face(context,
"mono",
CAIRO_FONT_SLANT_NORMAL,
CAIRO_FONT_WEIGHT_NORMAL);
cairo_set_font_size(context, 30);
cairo_move_to(context, WIDTH/2, HEIGHT/2);
cairo_show_text(context, argv[1]); // the text we got as a parameter
// draw a dotted box
const double pattern[] = {15.0, 10.0};
cairo_set_dash(context, pattern, 2, 0);
cairo_set_line_width(context, 5);
cairo_rectangle(context, WIDTH*0.33, HEIGHT*0.33, WIDTH*0.5, WIDTH*0.5);
cairo_stroke(context);
cairo_surface_t* surface_png = cairo_image_surface_create_from_png("background-img.png");
if (surface_png == NULL || cairo_surface_status (surface_png)) {
printf("***** load error *****\n");
}
widthPng = cairo_image_surface_get_width(surface_png);
heightPng = cairo_image_surface_get_height(surface_png);
cairo_surface_set_device_scale (surface_png,
widthPng/WIDTH*1.33,
heightPng/HEIGHT*1.29);
cairo_set_operator(context, CAIRO_OPERATOR_DEST_OVER);
cairo_set_source_surface(context, surface_png, 0, 0);
cairo_paint(context);
/*** second page ***/
{
cairo_t *cr;
cr = cairo_create (surface);
/* Duplicate the last frame onto another page. (This is just a
* way to sneak cairo_copy_page into the test).
*/
cairo_show_page (cr);
//draw text on second page
cairo_select_font_face(cr,
"mono",
CAIRO_FONT_SLANT_NORMAL,
CAIRO_FONT_WEIGHT_NORMAL);
cairo_set_font_size(cr, 30);
cairo_move_to(cr, WIDTH/2, HEIGHT/2);
cairo_show_text(cr, "text over second page");
cairo_set_operator(cr, CAIRO_OPERATOR_DEST_OVER);
cairo_set_source_surface(cr, surface_png, 0, 0);
cairo_paint(cr);
cairo_destroy (cr);
}
// finish up
cairo_show_page(context);
cairo_destroy(context);
cairo_surface_flush(surface);
cairo_surface_destroy(surface);
cairo_surface_flush(surface_png);
cairo_surface_destroy(surface_png);
// print
cupsPrintFile("Cups-PDF", tmpfilename, "cairo PS", 0, NULL);
unlink(tmpfilename);
return 0;
}
Update :
I added the text enclosed in "second page". I can create another page, but I can't resize the background image.
How can I resize the image to fit the A4 size?
Update
I used cairo_surface_set_device_scale to resize the image, and the mono font to use a fixed width font
Update
The problem now is that the code works with cairo-1.15.12-4 while if I try to compile with cairo-1.8.8-3.1 I get undefined reference to cairo_surface_set_device_scale'.
What can I solve the problem? At the moment I cannot update the libraries using rpm as I would have to update the whole operating system.
Can I somehow replace the cairo_surface_set_device_scale with functions that perform the same task?
Update:
In the Cairo Mailing Lists I found the following function that does the job :
cairo_surface_t *scale_to_half(cairo_surface_t *s, int orig_width, int
orig_height, double x_scale, double y_scale)
{
cairo_surface_t *result = cairo_surface_create_similar(s,
cairo_surface_get_content(s), orig_width*x_scale, orig_height*y_scale);
cairo_t *cr = cairo_create(result);
cairo_scale(cr, x_scale, y_scale);
cairo_set_source_surface(cr, s, 0, 0);
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
cairo_paint(cr);
cairo_destroy(cr);
return result;
}
but the quality is very low compared to cairo_surface_set_device_scale.

OpenCV canny; output image is pure gray

I am learning opencv and reading a book and following examples. The book introduced the canny filter. However there is some problem with my output. As an input image I have given a 512x512 gray scale image but the filter output is pure gray image. Here is the image:
This is the input image.
And this is the output image.
And here is the snippets:
#include <opencv\cv.h>
#include <opencv2\highgui\highgui.hpp>
#include "Resources.h"
IplImage* doCanny(
IplImage* in,
double lowThresh,
double highThresh,
double aperture
) {
if (in->nChannels != 1)
{
return 0; // Canny only handle gray scale images.
}
IplImage* out = cvCreateImage(
CvSize(cvGetSize(in)),
IPL_DEPTH_8U,
1
);
cvCanny(in, out, lowThresh, highThresh, aperture);
return out;
}
int main(int argc, char** argv)
{
IplImage* image = cvLoadImage(IMAGE_FRUIT);
IplImage* output = doCanny(image, 200, 201, 1);
cvNamedWindow("Canny", CV_WINDOW_AUTOSIZE);
cvShowImage("Canny", output);
cvWaitKey(0);
cvReleaseImage(&output);
cvDestroyWindow("Canny");
return 0;
}
Visual Studio 2015, OpenCV version 2.4.13
I think if you step through your code, you will realize the cvCanny function never gets triggered, the returned output from doCanny is a null pointer.
OpenCV's Canny edge detection algorithm only accepts gray scale image, which is why the original code has the "if (in->nChannels != 1)" check, so you need to convert your input image into a grayscale image first.
// Convert to grayscale first
IplImage* gray_image = cvCreateImage(cvGetSize(image), IPL_DEPTH_8U, 1);
cvCvtColor(image, gray_image, CV_BGR2GRAY);
// Perform Canny
IplImage* output = doCanny(gray_image, 200, 201, 3);
Additional, I think your "aperture" parameter for cvCanny is also invalid, try to use the default value 3 (or 5, 7), and you should be able to see the result.
I would also recommend using the C++ interface instead of the deprecated C interface.

Return type as Array of IPlImage

I spend the whole morning today searching for a way to save an array of images in IplImage type in openCV and failed.
This is what I am trying to do :
IplImage* GetThresholdedImage(IplImage* img) {
IplImage* imageTest[2];
IplImage* imgHSV = cvCreateImage(cvGetSize(img), 8, 3); // hold the resulted HSV image
cvCvtColor(img, imgHSV, CV_BGR2HSV); // convert the coming image from the camera from RGB format to HSV (Hue, Saturation, Value)
imageTest[0] = cvCreateImage(cvGetSize(img), 8, 1); //hold the thresholded image of the yellow color
imageTest[1] = cvCreateImage(cvGetSize(img), 8, 1); //hold the thresholded image of the red color
cvSmooth(imgHSV, imgHSV, CV_GAUSSIAN, 11, 11); //smooth the image to remove the noise from the image
cvInRangeS(imgHSV, cvScalar(24, 100, 150), cvScalar(34, 255, 255),
imageTest[0]); //this function filter out the colors in this range (This is a yellow color)
cvInRangeS(imgHSV, cvScalar(172, 100, 150), cvScalar(179, 255, 255),
imageTest[1]); //this function filter out the colors in this range (This is a red color)
cvReleaseImage(&imgHSV);
return *imageTest;
}
Now when I try to return the array in the main in order to process it -->
IplImage *thresholdedImage;// = cvCreateImage(cvGetSize(frame), 8, 1); // to store the thresholded image
IplImage *yellow = cvCreateImage(cvGetSize(frame), 8, 1);
IplImage *red = cvCreateImage(cvGetSize(frame), 8, 1);
//===========================================
// start creating three windows to show the video after being thresholded, after it passes the contour function and the final video
cvNamedWindow("display", CV_WINDOW_AUTOSIZE);
cvNamedWindow("Threshold", CV_WINDOW_AUTOSIZE);
cvNamedWindow("contoured", CV_WINDOW_AUTOSIZE);
while (key != 'q') { // grab the video unless the user press q button
frame = cvQueryFrame(capture);
if (!frame) {
break;
}
//start the actual video processing on real-time frames
//first output of the threshold method
thresholdedImage = GetThresholdedImage(frame);
yellow = *thresholdedImage;
red = *thresholdedImage++;
//insert the resulted frame from the above function into the find contour function
cvFindContours(yellow, storage, &contours, sizeof(CvContour),
CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, cvPoint(0, 0));
cvFindContours(red, storage, &contours, sizeof(CvContour),
CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, cvPoint(0, 0));
however it gives me error !!!
any help is appreciated , thank you
An array of pointers to IplImage would be IplImage**. Also note, that you have to provide the buffer from the outside, as you can't return a pointer to local (non-static) data.
void GetImages(IplImage** images, unsigned int num) {
// assign pointers here
images[0] = ...
images[1] = ...
}
IplImage *images[2];
GetImage(images, 2);
As an alternative, you could as well create the array within your function using new or malloc and return the pointer to it. Just ensure you delete/free it later on.
IplImage **CreateImages(unsigned int num) {
IplImage **images = new IplImage*[num];
// assign again
images[0] = ...
return images;
}
Also ensure you free the images, once you're done with them. So you shouldn't use the approach you used above (increasing the pointer). Instead simply use array syntax to access n-th element.
Your code fails due to returning only a single pointer to the first image instead of the actual array.

Inverse fill image in OpenCV

I'm new to OpenCv and have been using it for a small project.
I intend to fill a single channel image all over, except a rectangle region within the image.
I have two problems.
1) Filling a single channel image with black. (cvSet wont work on single channel)
2) Carrying out the fill all over the image except a rectangle region within the image.
Any solutions?
Here's a program that shows how to fill a single channel with black and also how to set the image to black with a mask.
#include <iostream>
#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
int main(int argc, const char * argv[]) {
cv::Mat image;
image = cv::imread("../../lena.jpg", CV_LOAD_IMAGE_GRAYSCALE);
if (!image.data) {
std::cout << "Image file not found\n";
return 1;
}
cv::namedWindow("original");
cv::imshow("original", image);
//Define the ROI rectangle
cv::Rect ROIrect(100, 100, 200, 200);
//Create a deep copy of the image
cv::Mat fill(image.clone());
//Specify the ROI
cv::Mat fillROI = fill(ROIrect);
//Fill the ROI with black
fillROI = cv::Scalar(0);
cv::namedWindow("fill");
cv::imshow("fill", fill);
cvMoveWindow("fill", 500, 40);
//create a deep copy of the image
cv::Mat inverseFill(image.clone());
//create a single-channel mask the same size as the image filled with 1
cv::Mat inverseMask(inverseFill.size(), CV_8UC1, cv::Scalar(1));
//Specify the ROI in the mask
cv::Mat inverseMaskROI = inverseMask(ROIrect);
//Fill the mask's ROI with 0
inverseMaskROI = cv::Scalar(0);
//Set the image to 0 in places where the mask is 1
inverseFill.setTo(cv::Scalar(0), inverseMask);
cv::namedWindow("inverseFill");
cv::imshow("inverseFill", inverseFill);
cvMoveWindow("inverseFill", 1000, 40);
// wait for key
cv::waitKey(0);
return 0;
}
Nested for loops would indeed be the quickest way.
Otherwise, consider making a buffer of identical size that's cleared using cvZero (all black). Then, setROI to the region that you care about, and cvCopy into the temporary buffer.
A bit mask with cvAnd is also a nice and clean solution.

OpenCV cvCanny memory exception

I am trying to do the examples in the OpenCV book and I got to the part regarding cvCanny. I am trying to use it, but I keep getting a memory exception error of
Unhandled exception at 0x75d8b760 in Image_Transform.exe: Microsoft C++ exception: cv::Exception at memory location 0x0011e7a4..
I have also looked at another post that was similar to this question, but it did not help for me as I got the same error each time. Any help is greatly appreciated and the source code for the function is located below.
void example2_4(IplImage* img)
{
// Create windows to show input and ouput images
cvNamedWindow("Example 2-4 IN", CV_WINDOW_AUTOSIZE);
cvNamedWindow("Example 2-4 OUT", CV_WINDOW_AUTOSIZE);
// Display out input image
cvShowImage("Example 2-4 IN", img);
// Create an image to hold our modified input image
IplImage* out = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, 3);
// Do some smoothing
//cvSmooth(img, out, CV_GAUSSIAN, 3, 3);
// Do some Edge detection
cvCanny(img, out, 10, 20, 3);
// Show the results
cvShowImage("Example 2-4 OUT", out);
// Release the memory used by the transformed image
cvReleaseImage(&out);
// Wait for user to hit a key then clean up the windows
cvWaitKey(0);
cvDestroyWindow("Example 2-4 IN");
cvDestroyWindow("Example 2-4 OUT");
}
int main()
{
// Load in an image
IplImage* img = cvLoadImage("images/00000038.jpg");
// Run the transform
example2_4(img);
// clean the image from memory
cvReleaseImage(&img);
return 0;
}
You forgot to say if you are able to see the original image being displayed on the screen.
I never get tired of telling people that checking the return of functions is a must!
Consider IplImage* img = cvLoadImage("images/00000038.jpg"); , how can you tell if this function succeeded or not? As far as I can tell, the error you are having might be from a function failing prior to cvCanny() being called.
Anyway, I recently posted a code that uses cvCanny to improve circle detection. You can check that code and see what you are doing differently.
EDIT:
Your problem in this case is that you are passing to cvCanny input and output as a 3 channel image, when it takes only a single channel image. Check the docs:
void cvCanny(const CvArr* image, CvArr* edges, double threshold1, double threshold2, int aperture_size=3)
Implements the Canny algorithm for edge detection.
Parameters:
* image – Single-channel input image
* edges – Single-channel image to store the edges found by the function
* threshold1 – The first threshold
* threshold2 – The second threshold
* aperture_size – Aperture parameter for the Sobel operator (see Sobel)
So, change your code to:
// Create an image to hold our modified input image
IplImage* out = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, 1);
// Do some smoothing
//cvSmooth(img, out, CV_GAUSSIAN, 3, 3);
IplImage* gray = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, 1);
cvCvtColor(img, gray, CV_BGR2GRAY);
// Do some Edge detection
cvCanny(gray, out, 10, 20, 3);

Resources