<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.elphel.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Andy753421</id>
	<title>ElphelWiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.elphel.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Andy753421"/>
	<link rel="alternate" type="text/html" href="https://wiki.elphel.com/wiki/Special:Contributions/Andy753421"/>
	<updated>2026-08-01T06:43:41Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.43.9</generator>
	<entry>
		<id>https://wiki.elphel.com/index.php?title=OpenCV_Tennis_balls_recognizing_tutorial&amp;diff=6097</id>
		<title>OpenCV Tennis balls recognizing tutorial</title>
		<link rel="alternate" type="text/html" href="https://wiki.elphel.com/index.php?title=OpenCV_Tennis_balls_recognizing_tutorial&amp;diff=6097"/>
		<updated>2009-06-20T16:10:20Z</updated>

		<summary type="html">&lt;p&gt;Andy753421: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This tutorial demonstrates how to use an Elphel (or perhaps another) camera to perform some basic computer vision tasks, such as identifying objects. For this example, we will be recognizing tennis balls. A  [[Image:Tennis.tar.gz|finished example]] is available for GNU/Linux systems.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
;OpenCV&lt;br /&gt;
:[http://opencv.willowgarage.com/wiki/ OpenCV] is a C library designed to help with computer vision programs. It provides quite a few useful functions that can save a lot typing when performing operations on images.&lt;br /&gt;
&lt;br /&gt;
;V4L/AVLD&lt;br /&gt;
:OpenCV provides a V4L API that can be used to acquire images from Elphel cameras. This is done using [[AVLD_-_Another_Video_Loopback_Device|AVLD]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Image acquisition ==&lt;br /&gt;
[[Image:Tennis-input.jpg|thumb|Example input image]]&lt;br /&gt;
&lt;br /&gt;
The first step is to get some images into OpenCV and display them. This assumes you have AVLD and V4L already set up. Below is a fairly minimal example that captures and displays images. It can be compiled with &#039;&#039;&#039;gcc -o main main.c $(pkg-config --libs --cflags opencv)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#include &amp;lt;opencv/cv.h&amp;gt;&lt;br /&gt;
#include &amp;lt;opencv/highgui.h&amp;gt;&lt;br /&gt;
#include &amp;lt;X11/keysym.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
int main(int argc, char **argv)&lt;br /&gt;
{&lt;br /&gt;
	/* Start the CV system and get the first v4l camera */&lt;br /&gt;
	cvInitSystem(argc, argv);&lt;br /&gt;
	CvCapture *cam = cvCreateCameraCapture(0);&lt;br /&gt;
&lt;br /&gt;
	/* Create a window to use for displaying the images */&lt;br /&gt;
	cvNamedWindow(&amp;quot;img&amp;quot;, 0);&lt;br /&gt;
	cvMoveWindow(&amp;quot;img&amp;quot;, 200, 200);&lt;br /&gt;
&lt;br /&gt;
	/* Display images until the user presses q */&lt;br /&gt;
	while (1) {&lt;br /&gt;
		cvGrabFrame(cam);&lt;br /&gt;
		IplImage *img = cvRetrieveFrame(cam);&lt;br /&gt;
		cvShowImage(&amp;quot;img&amp;quot;, img);&lt;br /&gt;
		if (cvWaitKey(10) == XK_q)&lt;br /&gt;
			return 0;&lt;br /&gt;
		cvReleaseImage(&amp;amp;img);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Processing ==&lt;br /&gt;
=== Color space ===&lt;br /&gt;
[[Image:Tennis-hsv.jpg|thumb|Example HSV output]]&lt;br /&gt;
&lt;br /&gt;
A good first step in many CV algorithms is to convert the image to [http://en.wikipedia.org/wiki/HSL_and_HSV HSV] (or another similar [http://en.wikipedia.org/wiki/Color_space color space]). This makes picking out objects based on colors a bit simpler, as will be seen later. We&#039;ll make a copy of the original image so that we can display the original at the end. Note that OpenCV stores images in BGR format by default.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	CvSize size = cvGetSize(img);&lt;br /&gt;
	IplImage *hsv = cvCreateImage(size, IPL_DEPTH_8U, 3);&lt;br /&gt;
	cvCvtColor(img, hsv, CV_BGR2HSV);  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Masks ===&lt;br /&gt;
[[Image:Tennis-mask.png|thumb|Example mask]]&lt;br /&gt;
&lt;br /&gt;
The next step is to select all pixels that we think might be part of a tennis ball. We&#039;ll do this based purely on their HSV values. OpenCV provides a InRanage function that can be used to pick out pixels based on their values. This generates a [http://en.wikipedia.org/wiki/Mask_(computing) mask]; a binary image where the foreground pixels (white) were within the specified range. We&#039;re done with the HSV image after this, so we can free it&#039;s memory.&lt;br /&gt;
&lt;br /&gt;
Picking the ranges for creating masks is one of the more complicated parts of a CV algorithm. For now, manually tuning the ranges is easiest. You might also use one of the OpenCV machine learning algorithms to pick the ranges automatically.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	CvMat *mask = cvCreateMat(size.height, size.width, CV_8UC1);&lt;br /&gt;
	cvInRangeS(hsv, cvScalar(0.11*256, 0.60*256, 0.20*256, 0),&lt;br /&gt;
	                cvScalar(0.14*256, 1.00*256, 1.00*256, 0), mask);&lt;br /&gt;
	cvReleaseImage(&amp;amp;hsv);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Morphological operations ===&lt;br /&gt;
[[Image:Tennis-morph.png|thumb|Mask after morphological operations]]&lt;br /&gt;
&lt;br /&gt;
No matter how good your ranges are when generating a mask, there will almost always be noise in the mask. In our example, the white lines on the tennis ball don&#039;t show up because they don&#039;t fit the hue range. Much of this nose can be eliminated by using a series of [http://en.wikipedia.org/wiki/Mathematical_morphology morphological operations]. Two commonly uses operation are [http://en.wikipedia.org/wiki/Opening_(morphology) opening] and [http://en.wikipedia.org/wiki/Closing_(morphology) closing], which are in turn comprised of [http://en.wikipedia.org/wiki/Dilation_(morphology) dilate] and [http://en.wikipedia.org/wiki/Erosion_(morphology) erode] operations. The table below summarizes these operations.&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
! Operation !! Effect / Use&lt;br /&gt;
|-&lt;br /&gt;
| Dilate || Expand the foreground&lt;br /&gt;
|-&lt;br /&gt;
| Erode  || Contract the foreground (~ expand background)&lt;br /&gt;
|-&lt;br /&gt;
| Close  || Dilation followed by erosion, removes specks of background, fills in foreground areas.&lt;br /&gt;
|-&lt;br /&gt;
| Open   || Erosion followed by dilation, removes specks of foreground, fills in background areas.&lt;br /&gt;
|} &lt;br /&gt;
&lt;br /&gt;
Morphological operations are performed with a [http://en.wikipedia.org/wiki/Structuring_element Structuring Element]. In computer vision, this is typically a oval or a rectangle of some specific size. Note that using rectangles results in faster code but can also cause poorer results.&lt;br /&gt;
&lt;br /&gt;
Below, we use a large rectangular structuring element along with a close to remove the black lines that show up in the tennis balls. Afterwards, we perform an open with a smaller structuring element to eliminate some additional nose from the image.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	IplConvKernel *se21 = cvCreateStructuringElementEx(21, 21, 10, 10, CV_SHAPE_RECT, NULL);&lt;br /&gt;
	IplConvKernel *se11 = cvCreateStructuringElementEx(11, 11, 5,  5,  CV_SHAPE_RECT, NULL);&lt;br /&gt;
	cvClose(mask, mask, se21); // See completed example for cvClose definition&lt;br /&gt;
	cvOpen(mask, mask, se11);  // See completed example for cvOpen  definition&lt;br /&gt;
	cvReleaseStructuringElement(&amp;amp;se21);&lt;br /&gt;
	cvReleaseStructuringElement(&amp;amp;se11);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Hough transform ===&lt;br /&gt;
The real work in finding tennis balls is done by a [http://en.wikipedia.org/wiki/Hough_transform Hough transform]. The specifics of this are beyond the scope of this tutorial. We&#039;ll just treat it as a black box function that finds circular objects in an input image.&lt;br /&gt;
&lt;br /&gt;
The OpenCV Hough function performs a [http://en.wikipedia.org/wiki/Canny_edge_detector Canny edge detection] on the input image before the actual Hough transform. Due to this and the way the Hough transform works, it is beneficial to do quite a bit of smoothing to get a nice gradient around the edge of the circles before passing the image to the Hough function. Many of the parameters to the Hough function can also be tuned to provide better results.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	/* Copy mask into a grayscale image */&lt;br /&gt;
	IplImage *hough_in = cvCreateImage(size, 8, 1);&lt;br /&gt;
	cvCopy(mask, hough_in, NULL);&lt;br /&gt;
        cvSmooth(hough_in, hough_in, CV_GAUSSIAN, 15, 15, 0, 0);&lt;br /&gt;
&lt;br /&gt;
	/* Run the Hough function */&lt;br /&gt;
	CvMemStorage *storage = cvCreateMemStorage(0);&lt;br /&gt;
	CvSeq *circles = cvHoughCircles(hough_in, storage,&lt;br /&gt;
		CV_HOUGH_GRADIENT, 4, size.height/10, 100, 40, 0, 0);&lt;br /&gt;
	cvReleaseMemStorage(&amp;amp;storage);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Output ==&lt;br /&gt;
[[Image:Tennis-output.jpg|thumb|Example output on a particularly nice image]]&lt;br /&gt;
&lt;br /&gt;
The output of the Hough function can then be used in a variety of ways. For now we&#039;ll just draw some circles and centers onto the original input image before displaying it.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	int i;&lt;br /&gt;
	for (i = 0; i &amp;lt; circles-&amp;gt;total; i++) {&lt;br /&gt;
             float *p = (float*)cvGetSeqElem(circles, i);&lt;br /&gt;
	     CvPoint center = cvPoint(cvRound(p[0]),cvRound(p[1]));&lt;br /&gt;
	     CvScalar val = cvGet2D(mask, center.y, center.x);&lt;br /&gt;
	     if (val.val[0] &amp;lt; 1) continue;&lt;br /&gt;
             cvCircle(img,  center, 3,             CV_RGB(0,255,0), -1, CV_AA, 0);&lt;br /&gt;
             cvCircle(img,  center, cvRound(p[2]), CV_RGB(255,0,0),  3, CV_AA, 0);&lt;br /&gt;
             cvCircle(mask, center, 3,             CV_RGB(0,255,0), -1, CV_AA, 0);&lt;br /&gt;
             cvCircle(mask, center, cvRound(p[2]), CV_RGB(255,0,0),  3, CV_AA, 0);&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Acknowledgments ==&lt;br /&gt;
Some of the code provided as part of this example was developed by Jon Nibert and Andy Spencer as part of the Image Recognition course taught at Rose-Hulman Institute of Technology. All examples are provided under the GNU GPLv3.&lt;/div&gt;</summary>
		<author><name>Andy753421</name></author>
	</entry>
	<entry>
		<id>https://wiki.elphel.com/index.php?title=Talk:OpenCV_Tennis_balls_recognizing_tutorial&amp;diff=6105</id>
		<title>Talk:OpenCV Tennis balls recognizing tutorial</title>
		<link rel="alternate" type="text/html" href="https://wiki.elphel.com/index.php?title=Talk:OpenCV_Tennis_balls_recognizing_tutorial&amp;diff=6105"/>
		<updated>2009-06-18T14:42:22Z</updated>

		<summary type="html">&lt;p&gt;Andy753421: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;I don&#039;t currently have an Elphel camera at my disposal anymore, so I was unable to test to make sure the image acquisition code in the tarball actually works. --[[User:Andy753421|Andy753421]]&lt;/div&gt;</summary>
		<author><name>Andy753421</name></author>
	</entry>
	<entry>
		<id>https://wiki.elphel.com/index.php?title=OpenCV_Tennis_balls_recognizing_tutorial&amp;diff=6096</id>
		<title>OpenCV Tennis balls recognizing tutorial</title>
		<link rel="alternate" type="text/html" href="https://wiki.elphel.com/index.php?title=OpenCV_Tennis_balls_recognizing_tutorial&amp;diff=6096"/>
		<updated>2009-06-18T14:40:06Z</updated>

		<summary type="html">&lt;p&gt;Andy753421: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This tutorial demonstrates how to use an Elphel (or perhaps another) camera to perform some basic computer vision tasks, such as identifying objects. For this example, we will be recognizing tennis balls. A  [[Image:Tennis.tar.gz|finished example]] is available for GNU/Linux systems.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
;OpenCV&lt;br /&gt;
:[http://opencv.willowgarage.com/wiki/ OpenCV] is a C library designed to help with computer vision programs. It provides quite a few useful functions that can save a lot typing when performing operations on images.&lt;br /&gt;
&lt;br /&gt;
;V4L/AVLD&lt;br /&gt;
:OpenCV provides a V4L API that can be used to acquire images from Elphel cameras. This is done using [[AVLD_-_Another_Video_Loopback_Device|AVLD]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Image acquisition ==&lt;br /&gt;
[[Image:Tennis-input.jpg|thumb|Example input image]]&lt;br /&gt;
&lt;br /&gt;
The first step is to get some images into OpenCV and display them. This assumes you have AVLD and V4L already set up. Below is a fairly minimal example that captures and displays images. It can be compiled with &#039;&#039;&#039;gcc -o main main.c $(pkg-config --libs --cflags opencv)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#include &amp;lt;opencv/cv.h&amp;gt;&lt;br /&gt;
#include &amp;lt;opencv/highgui.h&amp;gt;&lt;br /&gt;
#include &amp;lt;X11/keysym.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
int main(int argc, char **argv)&lt;br /&gt;
{&lt;br /&gt;
	/* Start the CV system and get the first v4l camera */&lt;br /&gt;
	cvInitSystem(argc, argv);&lt;br /&gt;
	CvCapture *cam = cvCreateCameraCapture(0);&lt;br /&gt;
&lt;br /&gt;
	/* Create a window to use for displaying the images */&lt;br /&gt;
	cvNamedWindow(&amp;quot;img&amp;quot;, 0);&lt;br /&gt;
	cvMoveWindow(&amp;quot;img&amp;quot;, 200, 200);&lt;br /&gt;
&lt;br /&gt;
	/* Display images until the user presses q */&lt;br /&gt;
	while (1) {&lt;br /&gt;
		cvGrabFrame(cam);&lt;br /&gt;
		IplImage *img = cvRetrieveFrame(cam);&lt;br /&gt;
		cvShowImage(&amp;quot;img&amp;quot;, img);&lt;br /&gt;
		if (cvWaitKey(10) == XK_q)&lt;br /&gt;
			return 0;&lt;br /&gt;
		cvReleaseImage(&amp;amp;img);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Processing ==&lt;br /&gt;
=== Color space ===&lt;br /&gt;
[[Image:Tennis-hsv.jpg|thumb|Example HSV output]]&lt;br /&gt;
&lt;br /&gt;
A good first step in many CV algorithms is to convert the image to [http://en.wikipedia.org/wiki/HSL_and_HSV HSV] (or another similar [http://en.wikipedia.org/wiki/Color_space color space]). This make picking out objects based on colors a bit simpler as will be seen later. We&#039;ll make a copy of the original image so that we can display it at the end. Note that OpenCV stores images in BGR format by default.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	CvSize size = cvGetSize(img);&lt;br /&gt;
	IplImage *hsv = cvCreateImage(size, IPL_DEPTH_8U, 3);&lt;br /&gt;
	cvCvtColor(img, hsv, CV_BGR2HSV);  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Masks ===&lt;br /&gt;
[[Image:Tennis-mask.png|thumb|Example mask]]&lt;br /&gt;
&lt;br /&gt;
The next step is to select all pixels that we think might be part of a tennis ball. We&#039;ll do this based purely on their HSV values. OpenCV provides a InRanage function that can be used  to pick out pixels based on their values. This generates a [http://en.wikipedia.org/wiki/Mask_(computing) mask]; a binary image where the foreground (white) pixels were with in the specified range. We&#039;re done with the HSV image after this, so we can free it&#039;s memory.&lt;br /&gt;
&lt;br /&gt;
Picking the ranges for creating mask is one of the more complicated parts of a CV algorithm. For now, manually tuning the values is easiest. You could also use a machine learning algorithm to pick the ranges automatically.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	CvMat *mask = cvCreateMat(size.height, size.width, CV_8UC1);&lt;br /&gt;
	cvInRangeS(hsv, cvScalar(0.11*256, 0.60*256, 0.20*256, 0),&lt;br /&gt;
	                cvScalar(0.14*256, 1.00*256, 1.00*256, 0), mask);&lt;br /&gt;
	cvReleaseImage(&amp;amp;hsv);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Morphological operations ===&lt;br /&gt;
[[Image:Tennis-morph.png|thumb|Mask after morphological operations]]&lt;br /&gt;
&lt;br /&gt;
No matter how good your ranges are when generating a mask, there will almost always be noise in the mask. In our example, the white lines on the tennis ball don&#039;t show up because they don&#039;t fit the hue range. Much of this nose can be eliminated by using a series of [http://en.wikipedia.org/wiki/Mathematical_morphology morphological operations]. Two commonly uses operation are [http://en.wikipedia.org/wiki/Opening_(morphology) opening] and [http://en.wikipedia.org/wiki/Closing_(morphology) closing], which are in turn comprised of [http://en.wikipedia.org/wiki/Dilation_(morphology) dilate] and [http://en.wikipedia.org/wiki/Erosion_(morphology) erode] operations. The table below summarizes these operations.&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
! Operation !! Effect / Use&lt;br /&gt;
|-&lt;br /&gt;
| Dilate || Expand the foreground&lt;br /&gt;
|-&lt;br /&gt;
| Erode  || contract the foreground (~ expand background)&lt;br /&gt;
|-&lt;br /&gt;
| Close  || Dilation followed by erosion, removes specks of background, fills in foreground areas.&lt;br /&gt;
|-&lt;br /&gt;
| Open   || Erosion followed by dilation, removes specks of foreground, fills in background areas.&lt;br /&gt;
|} &lt;br /&gt;
&lt;br /&gt;
Morphological operations are performed with a [http://en.wikipedia.org/wiki/Structuring_element Structuring Element]. In computer vision, this is typically a oval or a rectangle of some specific size. Note that using rectangles results in faster code but can also cause poorer results.&lt;br /&gt;
&lt;br /&gt;
Below, we use a large rectangular structuring element along with a close to remove the black lines that show up in the tennis balls. Afterwards we perform an open with a smaller structuring element to eliminate some additional nose from the image.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	IplConvKernel *se21 = cvCreateStructuringElementEx(21, 21, 10, 10, CV_SHAPE_RECT, NULL);&lt;br /&gt;
	IplConvKernel *se11 = cvCreateStructuringElementEx(11, 11, 5,  5,  CV_SHAPE_RECT, NULL);&lt;br /&gt;
	cvClose(mask, mask, se21);&lt;br /&gt;
	cvOpen(mask, mask, se11);&lt;br /&gt;
	cvReleaseStructuringElement(&amp;amp;se21);&lt;br /&gt;
	cvReleaseStructuringElement(&amp;amp;se11);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Hough transform ===&lt;br /&gt;
The real work in finding tennis balls is done by a [http://en.wikipedia.org/wiki/Hough_transform Hough transform]. The specifics of this are beyond the scope of this tutorial. We&#039;ll just treat it as a black box function that finds circular objects in a gray input image.&lt;br /&gt;
&lt;br /&gt;
The OpenCV Hough function performs a [http://en.wikipedia.org/wiki/Canny_edge_detector Canny edge detection] on the input image before doing running the actual Hough transform. Due to this and the way the Hough transform works, it is beneficial to do quite a bit of smoothing to get a nice gradient around the edge of the circles before passing the image to the Hough function. Many of the parameters to the Hough function can also be tuned to provide better results.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	/* Copy mask into a gray scale image */&lt;br /&gt;
	IplImage *hough_in = cvCreateImage(size, 8, 1);&lt;br /&gt;
	cvCopy(mask, hough_in, NULL);&lt;br /&gt;
        cvSmooth(hough_in, hough_in, CV_GAUSSIAN, 15, 15, 0, 0);&lt;br /&gt;
&lt;br /&gt;
	/* Run the Hough function */&lt;br /&gt;
	CvMemStorage *storage = cvCreateMemStorage(0);&lt;br /&gt;
	CvSeq *circles = cvHoughCircles(hough_in, storage,&lt;br /&gt;
		CV_HOUGH_GRADIENT, 4, size.height/10, 100, 40, 0, 0);&lt;br /&gt;
	cvReleaseMemStorage(&amp;amp;storage);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Output ==&lt;br /&gt;
[[Image:Tennis-output.jpg|thumb|Example output on a particularly nice image]]&lt;br /&gt;
&lt;br /&gt;
The output of the Hough function can then be used in a variety of ways. For now we&#039;ll just draw some circles and centers onto the original input image before displaying it.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	int i;&lt;br /&gt;
	for (i = 0; i &amp;lt; circles-&amp;gt;total; i++) {&lt;br /&gt;
             float *p = (float*)cvGetSeqElem(circles, i);&lt;br /&gt;
	     CvPoint center = cvPoint(cvRound(p[0]),cvRound(p[1]));&lt;br /&gt;
	     CvScalar val = cvGet2D(mask, center.y, center.x);&lt;br /&gt;
	     if (val.val[0] &amp;lt; 1) continue;&lt;br /&gt;
             cvCircle(img,  center, 3,             CV_RGB(0,255,0), -1, CV_AA, 0);&lt;br /&gt;
             cvCircle(img,  center, cvRound(p[2]), CV_RGB(255,0,0),  3, CV_AA, 0);&lt;br /&gt;
             cvCircle(mask, center, 3,             CV_RGB(0,255,0), -1, CV_AA, 0);&lt;br /&gt;
             cvCircle(mask, center, cvRound(p[2]), CV_RGB(255,0,0),  3, CV_AA, 0);&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Acknowledgments ==&lt;br /&gt;
Some of the code provided as part of this example was developed by Jon Nibert and Andy Spencer as part of the Image Recognition course taught at Rose-Hulman Institute of Technology. All examples are provided under the GNU GPLv3.&lt;/div&gt;</summary>
		<author><name>Andy753421</name></author>
	</entry>
	<entry>
		<id>https://wiki.elphel.com/index.php?title=OpenCV_Tennis_balls_recognizing_tutorial&amp;diff=6095</id>
		<title>OpenCV Tennis balls recognizing tutorial</title>
		<link rel="alternate" type="text/html" href="https://wiki.elphel.com/index.php?title=OpenCV_Tennis_balls_recognizing_tutorial&amp;diff=6095"/>
		<updated>2009-06-18T14:30:15Z</updated>

		<summary type="html">&lt;p&gt;Andy753421: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This tutorial demonstrates how to use an Elphel (or perhaps another) camera to perform some basic computer vision tasks, such as identifying objects. For this example, we will be recognizing tennis balls. A  [[Image:Tennis.tar.gz|finished example]] is available for GNU/Linux systems.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
;OpenCV&lt;br /&gt;
:[http://opencv.willowgarage.com/wiki/ OpenCV] is a C library designed to help with computer vision programs. It provides quite a few useful functions that can save a lot typing when performing operations on images.&lt;br /&gt;
&lt;br /&gt;
;V4L/AVLD&lt;br /&gt;
:OpenCV provides a V4L API that can be used to acquire images from Elphel cameras. This is done using [[AVLD_-_Another_Video_Loopback_Device|AVLD]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Image acquisition ==&lt;br /&gt;
[[Image:Tennis-input.jpg|thumb|Example input image]]&lt;br /&gt;
&lt;br /&gt;
The first step is to get some images into OpenCV and display them. This assumes you have AVLD and V4L already set up. Below is a fairly minimal example that captures and displays images. It can be compiled with &#039;&#039;&#039;gcc -o main main.c $(pkg-config --libs --cflags opencv)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#include &amp;lt;opencv/cv.h&amp;gt;&lt;br /&gt;
#include &amp;lt;opencv/highgui.h&amp;gt;&lt;br /&gt;
#include &amp;lt;X11/keysym.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
int main(int argc, char **argv)&lt;br /&gt;
{&lt;br /&gt;
	/* Start the CV system and get the first v4l camera */&lt;br /&gt;
	cvInitSystem(argc, argv);&lt;br /&gt;
	CvCapture *cam = cvCreateCameraCapture(0);&lt;br /&gt;
&lt;br /&gt;
	/* Create a window to use for displaying the images */&lt;br /&gt;
	cvNamedWindow(&amp;quot;img&amp;quot;, 0);&lt;br /&gt;
	cvMoveWindow(&amp;quot;img&amp;quot;, 200, 200);&lt;br /&gt;
&lt;br /&gt;
	/* Display images until the user presses q */&lt;br /&gt;
	while (1) {&lt;br /&gt;
		cvGrabFrame(cam);&lt;br /&gt;
		IplImage *img = cvRetrieveFrame(cam);&lt;br /&gt;
		cvShowImage(&amp;quot;img&amp;quot;, img);&lt;br /&gt;
		if (cvWaitKey(10) == XK_q)&lt;br /&gt;
			return 0;&lt;br /&gt;
		cvReleaseImage(&amp;amp;img);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Processing ==&lt;br /&gt;
=== Color space ===&lt;br /&gt;
[[Image:Tennis-hsv.jpg|thumb|Example HSV output]]&lt;br /&gt;
&lt;br /&gt;
A good first step in many CV algorithms is to convert the image to HSV (or another similar color space). This make picking out objects based on colors a bit simpler as will be seen later. We&#039;ll make a copy of the original image so that we can display it at the end. Note that OpenCV stores images in BGR format by default.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	CvSize size = cvGetSize(img);&lt;br /&gt;
	IplImage *hsv = cvCreateImage(size, IPL_DEPTH_8U, 3);&lt;br /&gt;
	cvCvtColor(img, hsv, CV_BGR2HSV);  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Masks ===&lt;br /&gt;
[[Image:Tennis-mask.png|thumb|Example mask]]&lt;br /&gt;
&lt;br /&gt;
The next step is to select all pixels that we think might be part of a tennis ball. We&#039;ll do this based purely on their HSV values. OpenCV provides a InRanage function that can be used  to pick out pixels based on their values. This generates a mask; a binary image where the foreground (white) pixels were with in the specified range. We&#039;re done with the HSV image after this, so we can free it&#039;s memory.&lt;br /&gt;
&lt;br /&gt;
Picking the ranges for creating mask is one of the more complicated parts of a CV algorithm. For now, manually tuning the values is easiest. You could also use a machine learning algorithm to pick the ranges automatically.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	CvMat *mask = cvCreateMat(size.height, size.width, CV_8UC1);&lt;br /&gt;
	cvInRangeS(hsv, cvScalar(0.11*256, 0.60*256, 0.20*256, 0),&lt;br /&gt;
	                cvScalar(0.14*256, 1.00*256, 1.00*256, 0), mask);&lt;br /&gt;
	cvReleaseImage(&amp;amp;hsv);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Morphological operations ===&lt;br /&gt;
[[Image:Tennis-morph.png|thumb|Mask after morphological operations]]&lt;br /&gt;
&lt;br /&gt;
No matter how good your ranges are when generating a mask, there will almost always be noise in the mask. In our example, the white lines on the tennis ball don&#039;t show up because they don&#039;t fit the hue range. Much of this nose can be eliminated by using a series of morphological operations. Two commonly uses operation are [http://en.wikipedia.org/wiki/Opening_(morphology) opening] and [http://en.wikipedia.org/wiki/Closing_(morphology) closing], which are in turn comprised of [http://en.wikipedia.org/wiki/Dilation_(morphology) dilate] and [http://en.wikipedia.org/wiki/Erosion_(morphology) erode] operations. The table below summarizes these operations.&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
! Operation !! Effect / Use&lt;br /&gt;
|-&lt;br /&gt;
| Dilate || Expand the foreground&lt;br /&gt;
|-&lt;br /&gt;
| Erode  || contract the foreground (~ expand background)&lt;br /&gt;
|-&lt;br /&gt;
| Close  || Dilation followed by erosion, removes specks of background, fills in foreground areas.&lt;br /&gt;
|-&lt;br /&gt;
| Open   || Erosion followed by dilation, removes specks of foreground, fills in background areas.&lt;br /&gt;
|} &lt;br /&gt;
&lt;br /&gt;
Morphological operations are performed with a [http://en.wikipedia.org/wiki/Structuring_element Structuring Element]. In computer vision, this is typically a oval or a rectangle of some specific size. Note that using rectangles results in faster code but can also cause poorer results.&lt;br /&gt;
&lt;br /&gt;
Below, we use a large rectangular structuring element along with a close to remove the black lines that show up in the tennis balls. Afterwards we perform an open with a smaller structuring element to eliminate some additional nose from the image.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	IplConvKernel *se21 = cvCreateStructuringElementEx(21, 21, 10, 10, CV_SHAPE_RECT, NULL);&lt;br /&gt;
	IplConvKernel *se11 = cvCreateStructuringElementEx(11, 11, 5,  5,  CV_SHAPE_RECT, NULL);&lt;br /&gt;
	cvClose(mask, mask, se21);&lt;br /&gt;
	cvOpen(mask, mask, se11);&lt;br /&gt;
	cvReleaseStructuringElement(&amp;amp;se21);&lt;br /&gt;
	cvReleaseStructuringElement(&amp;amp;se11);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Hough transform ===&lt;br /&gt;
The real work in finding tennis balls is done by a Hough transform. The specifics of this are beyond the scope of this tutorial. We&#039;ll just treat it as a black box function that finds circular objects in a gray input image.&lt;br /&gt;
&lt;br /&gt;
The OpenCV Hough function performs a Canny edge detection on the input image before doing running the actual Hough transform. Due to this and the way the Hough transform works, it is beneficial to do quite a bit of smoothing to get a nice gradient around the edge of the circles before passing the image to the Hough function. Many of the parameters to the Hough function can also be tuned to provide better results.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	/* Copy mask into a gray scale image */&lt;br /&gt;
	IplImage *hough_in = cvCreateImage(size, 8, 1);&lt;br /&gt;
	cvCopy(mask, hough_in, NULL);&lt;br /&gt;
        cvSmooth(hough_in, hough_in, CV_GAUSSIAN, 15, 15, 0, 0);&lt;br /&gt;
&lt;br /&gt;
	/* Run the Hough function */&lt;br /&gt;
	CvMemStorage *storage = cvCreateMemStorage(0);&lt;br /&gt;
	CvSeq *circles = cvHoughCircles(hough_in, storage,&lt;br /&gt;
		CV_HOUGH_GRADIENT, 4, size.height/10, 100, 40, 0, 0);&lt;br /&gt;
	cvReleaseMemStorage(&amp;amp;storage);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Output ==&lt;br /&gt;
[[Image:Tennis-output.jpg|thumb|Example output on a particularly nice image]]&lt;br /&gt;
&lt;br /&gt;
The output of the Hough function can then be used in a variety of ways. For now we&#039;ll just draw some circles and centers onto the original input image before displaying it.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	int i;&lt;br /&gt;
	for (i = 0; i &amp;lt; circles-&amp;gt;total; i++) {&lt;br /&gt;
             float *p = (float*)cvGetSeqElem(circles, i);&lt;br /&gt;
	     CvPoint center = cvPoint(cvRound(p[0]),cvRound(p[1]));&lt;br /&gt;
	     CvScalar val = cvGet2D(mask, center.y, center.x);&lt;br /&gt;
	     if (val.val[0] &amp;lt; 1) continue;&lt;br /&gt;
             cvCircle(img,  center, 3,             CV_RGB(0,255,0), -1, CV_AA, 0);&lt;br /&gt;
             cvCircle(img,  center, cvRound(p[2]), CV_RGB(255,0,0),  3, CV_AA, 0);&lt;br /&gt;
             cvCircle(mask, center, 3,             CV_RGB(0,255,0), -1, CV_AA, 0);&lt;br /&gt;
             cvCircle(mask, center, cvRound(p[2]), CV_RGB(255,0,0),  3, CV_AA, 0);&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Acknowledgments ==&lt;br /&gt;
Some of the code provided as part of this example was developed by Jon Nibert and Andy Spencer as part of the Image Recognition course taught at Rose-Hulman Institute of Technology. All examples are provided under the GNU GPLv3.&lt;/div&gt;</summary>
		<author><name>Andy753421</name></author>
	</entry>
	<entry>
		<id>https://wiki.elphel.com/index.php?title=File:Tennis-output.jpg&amp;diff=6104</id>
		<title>File:Tennis-output.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.elphel.com/index.php?title=File:Tennis-output.jpg&amp;diff=6104"/>
		<updated>2009-06-18T14:25:03Z</updated>

		<summary type="html">&lt;p&gt;Andy753421: Output of OpenCV tennis ball finder&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Output of OpenCV tennis ball finder&lt;/div&gt;</summary>
		<author><name>Andy753421</name></author>
	</entry>
	<entry>
		<id>https://wiki.elphel.com/index.php?title=File:Tennis-morph.png&amp;diff=6103</id>
		<title>File:Tennis-morph.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.elphel.com/index.php?title=File:Tennis-morph.png&amp;diff=6103"/>
		<updated>2009-06-18T14:24:46Z</updated>

		<summary type="html">&lt;p&gt;Andy753421: Cleaned up mask for OpenCV tennis ball finder&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Cleaned up mask for OpenCV tennis ball finder&lt;/div&gt;</summary>
		<author><name>Andy753421</name></author>
	</entry>
	<entry>
		<id>https://wiki.elphel.com/index.php?title=File:Tennis-mask.png&amp;diff=6102</id>
		<title>File:Tennis-mask.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.elphel.com/index.php?title=File:Tennis-mask.png&amp;diff=6102"/>
		<updated>2009-06-18T14:24:28Z</updated>

		<summary type="html">&lt;p&gt;Andy753421: Mask for OpenCV tennis ball finder&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Mask for OpenCV tennis ball finder&lt;/div&gt;</summary>
		<author><name>Andy753421</name></author>
	</entry>
	<entry>
		<id>https://wiki.elphel.com/index.php?title=File:Tennis-hsv.jpg&amp;diff=6101</id>
		<title>File:Tennis-hsv.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.elphel.com/index.php?title=File:Tennis-hsv.jpg&amp;diff=6101"/>
		<updated>2009-06-18T14:24:11Z</updated>

		<summary type="html">&lt;p&gt;Andy753421: HSV for OpenCV tennis ball finder&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;HSV for OpenCV tennis ball finder&lt;/div&gt;</summary>
		<author><name>Andy753421</name></author>
	</entry>
	<entry>
		<id>https://wiki.elphel.com/index.php?title=File:Tennis-input.jpg&amp;diff=6100</id>
		<title>File:Tennis-input.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.elphel.com/index.php?title=File:Tennis-input.jpg&amp;diff=6100"/>
		<updated>2009-06-18T14:23:48Z</updated>

		<summary type="html">&lt;p&gt;Andy753421: Input for OpenCV tennis ball finder&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Input for OpenCV tennis ball finder&lt;/div&gt;</summary>
		<author><name>Andy753421</name></author>
	</entry>
	<entry>
		<id>https://wiki.elphel.com/index.php?title=File:Tennis.tar.gz&amp;diff=6099</id>
		<title>File:Tennis.tar.gz</title>
		<link rel="alternate" type="text/html" href="https://wiki.elphel.com/index.php?title=File:Tennis.tar.gz&amp;diff=6099"/>
		<updated>2009-06-18T14:14:14Z</updated>

		<summary type="html">&lt;p&gt;Andy753421: Example OpenCV code to find tennis balls&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Example OpenCV code to find tennis balls&lt;/div&gt;</summary>
		<author><name>Andy753421</name></author>
	</entry>
	<entry>
		<id>https://wiki.elphel.com/index.php?title=OpenCV_Tennis_balls_recognizing_tutorial&amp;diff=6094</id>
		<title>OpenCV Tennis balls recognizing tutorial</title>
		<link rel="alternate" type="text/html" href="https://wiki.elphel.com/index.php?title=OpenCV_Tennis_balls_recognizing_tutorial&amp;diff=6094"/>
		<updated>2009-06-18T13:55:21Z</updated>

		<summary type="html">&lt;p&gt;Andy753421: /* Acknowledgments */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This tutorial demonstrates how to use an Elphel (or perhaps another) camera to perform some basic computer vision tasks, such as identifying objects. For this example, we will be recognizing tennis balls.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
;OpenCV&lt;br /&gt;
:[http://opencv.willowgarage.com/wiki/ OpenCV] is a C library designed to help with computer vision programs. It provides quite a few useful functions that can save a lot typing when performing operations on images.&lt;br /&gt;
&lt;br /&gt;
;V4L/AVLD&lt;br /&gt;
:OpenCV provides a V4L API that can be used to acquire images from Elphel cameras. This is done using [[AVLD_-_Another_Video_Loopback_Device|AVLD]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Image acquisition ==&lt;br /&gt;
The first step is to get some images into OpenCV and display them. This assumes you have AVLD and V4L already set up. Below is a fairly minimal example that captures and displays images. It can be compiled with &#039;&#039;&#039;gcc -o main main.c $(pkg-config --libs --cflags opencv)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#include &amp;lt;opencv/cv.h&amp;gt;&lt;br /&gt;
#include &amp;lt;opencv/highgui.h&amp;gt;&lt;br /&gt;
#include &amp;lt;X11/keysym.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
int main(int argc, char **argv)&lt;br /&gt;
{&lt;br /&gt;
	/* Start the CV system and get the first v4l camera */&lt;br /&gt;
	cvInitSystem(argc, argv);&lt;br /&gt;
	CvCapture *cam = cvCreateCameraCapture(0);&lt;br /&gt;
&lt;br /&gt;
	/* Create a window to use for displaying the images */&lt;br /&gt;
	cvNamedWindow(&amp;quot;img&amp;quot;, 0);&lt;br /&gt;
	cvMoveWindow(&amp;quot;img&amp;quot;, 200, 200);&lt;br /&gt;
&lt;br /&gt;
	/* Display images until the user presses q */&lt;br /&gt;
	while (1) {&lt;br /&gt;
		cvGrabFrame(cam);&lt;br /&gt;
		IplImage *img = cvRetrieveFrame(cam);&lt;br /&gt;
		cvShowImage(&amp;quot;img&amp;quot;, img);&lt;br /&gt;
		if (cvWaitKey(10) == XK_q)&lt;br /&gt;
			return 0;&lt;br /&gt;
		cvReleaseImage(&amp;amp;img);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Processing ==&lt;br /&gt;
=== Color space ===&lt;br /&gt;
A good first step in many CV algorithms is to convert the image to HSV (or another similar color space). This make picking out objects based on colors a bit simpler as will be seen later. We&#039;ll make a copy of the original image so that we can display it at the end. Note that OpenCV stores images in BGR format by default.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	CvSize size = cvGetSize(img);&lt;br /&gt;
	IplImage *hsv = cvCreateImage(size, IPL_DEPTH_8U, 3);&lt;br /&gt;
	cvCvtColor(img, hsv, CV_BGR2HSV);  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Masks ===&lt;br /&gt;
The next step is to select all pixels that we think might be part of a tennis ball. We&#039;ll do this based purely on their HSV values. OpenCV provides a InRanage function that can be used  to pick out pixels based on their values. This generates a mask; a binary image where the foreground (white) pixels were with in the specified range. We&#039;re done with the HSV image after this, so we can free it&#039;s memory.&lt;br /&gt;
&lt;br /&gt;
Picking the ranges for creating mask is one of the more complicated parts of a CV algorithm. For now, manually tuning the values is easiest. You could also use a machine learning algorithm to pick the ranges automatically.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	CvMat *mask = cvCreateMat(size.height, size.width, CV_8UC1);&lt;br /&gt;
	cvInRangeS(hsv, cvScalar(0.11*256, 0.60*256, 0.20*256, 0),&lt;br /&gt;
	                cvScalar(0.14*256, 1.00*256, 1.00*256, 0), mask);&lt;br /&gt;
	cvReleaseImage(&amp;amp;hsv);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Morphological operations ===&lt;br /&gt;
No matter how good your ranges are when generating a mask, there will almost always be noise in the mask. In our example, the white lines on the tennis ball don&#039;t show up because they don&#039;t fit the hue range. Much of this nose can be eliminated by using a series of morphological operations. Two commonly uses operation are [http://en.wikipedia.org/wiki/Opening_(morphology) opening] and [http://en.wikipedia.org/wiki/Closing_(morphology) closing], which are in turn comprised of [http://en.wikipedia.org/wiki/Dilation_(morphology) dilate] and [http://en.wikipedia.org/wiki/Erosion_(morphology) erode] operations. The table below summarizes these operations.&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
! Operation !! Effect / Use&lt;br /&gt;
|-&lt;br /&gt;
| Dilate || Expand the foreground&lt;br /&gt;
|-&lt;br /&gt;
| Erode  || contract the foreground (~ expand background)&lt;br /&gt;
|-&lt;br /&gt;
| Close  || Dilation followed by erosion, removes specks of background, fills in foreground areas.&lt;br /&gt;
|-&lt;br /&gt;
| Open   || Erosion followed by dilation, removes specks of foreground, fills in background areas.&lt;br /&gt;
|} &lt;br /&gt;
&lt;br /&gt;
Morphological operations are performed with a [http://en.wikipedia.org/wiki/Structuring_element Structuring Element]. In computer vision, this is typically a oval or a rectangle of some specific size. Note that using rectangles results in faster code but can also cause poorer results.&lt;br /&gt;
&lt;br /&gt;
Below, we use a large rectangular structuring element along with a close to remove the black lines that show up in the tennis balls. Afterwards we perform an open with a smaller structuring element to eliminate some additional nose from the image.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	IplConvKernel *se21 = cvCreateStructuringElementEx(21, 21, 10, 10, CV_SHAPE_RECT, NULL);&lt;br /&gt;
	IplConvKernel *se11 = cvCreateStructuringElementEx(11, 11, 5,  5,  CV_SHAPE_RECT, NULL);&lt;br /&gt;
	cvClose(mask, mask, se21);&lt;br /&gt;
	cvOpen(mask, mask, se11);&lt;br /&gt;
	cvReleaseStructuringElement(&amp;amp;se21);&lt;br /&gt;
	cvReleaseStructuringElement(&amp;amp;se11);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Hough transform ===&lt;br /&gt;
The real work in finding tennis balls is done by a Hough transform. The specifics of this are beyond the scope of this tutorial. We&#039;ll just treat it as a black box function that finds circular objects in a gray input image.&lt;br /&gt;
&lt;br /&gt;
The OpenCV Hough function performs a Canny edge detection on the input image before doing running the actual Hough transform. Due to this and the way the Hough transform works, it is beneficial to do quite a bit of smoothing to get a nice gradient around the edge of the circles before passing the image to the Hough function. Many of the parameters to the Hough function can also be tuned to provide better results.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	/* Copy mask into a gray scale image */&lt;br /&gt;
	IplImage *hough_in = cvCreateImage(size, 8, 1);&lt;br /&gt;
	cvCopy(mask, hough_in, NULL);&lt;br /&gt;
        cvSmooth(hough_in, hough_in, CV_GAUSSIAN, 15, 15, 0, 0);&lt;br /&gt;
&lt;br /&gt;
	/* Run the Hough function */&lt;br /&gt;
	CvMemStorage *storage = cvCreateMemStorage(0);&lt;br /&gt;
	CvSeq *circles = cvHoughCircles(hough_in, storage,&lt;br /&gt;
		CV_HOUGH_GRADIENT, 4, size.height/10, 100, 40, 0, 0);&lt;br /&gt;
	cvReleaseMemStorage(&amp;amp;storage);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Output ==&lt;br /&gt;
The output of the Hough function can then be used in a variety of ways. For now we&#039;ll just draw some circles and centers onto the original input image before displaying it.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	int i;&lt;br /&gt;
	for (i = 0; i &amp;lt; circles-&amp;gt;total; i++) {&lt;br /&gt;
             float *p = (float*)cvGetSeqElem(circles, i);&lt;br /&gt;
	     CvPoint center = cvPoint(cvRound(p[0]),cvRound(p[1]));&lt;br /&gt;
	     CvScalar val = cvGet2D(mask, center.y, center.x);&lt;br /&gt;
	     if (val.val[0] &amp;lt; 1) continue;&lt;br /&gt;
             cvCircle(img,  center, 3,             CV_RGB(0,255,0), -1, CV_AA, 0);&lt;br /&gt;
             cvCircle(img,  center, cvRound(p[2]), CV_RGB(255,0,0),  3, CV_AA, 0);&lt;br /&gt;
             cvCircle(mask, center, 3,             CV_RGB(0,255,0), -1, CV_AA, 0);&lt;br /&gt;
             cvCircle(mask, center, cvRound(p[2]), CV_RGB(255,0,0),  3, CV_AA, 0);&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Acknowledgments ==&lt;br /&gt;
Some of the code provided as part of this example was developed by Jon Nibert and Andy Spencer as part of the Image Recognition course taught at Rose-Hulman Institute of Technology. All examples are provided under the GNU GPLv3.&lt;/div&gt;</summary>
		<author><name>Andy753421</name></author>
	</entry>
	<entry>
		<id>https://wiki.elphel.com/index.php?title=OpenCV_Tennis_balls_recognizing_tutorial&amp;diff=6093</id>
		<title>OpenCV Tennis balls recognizing tutorial</title>
		<link rel="alternate" type="text/html" href="https://wiki.elphel.com/index.php?title=OpenCV_Tennis_balls_recognizing_tutorial&amp;diff=6093"/>
		<updated>2009-06-18T13:51:46Z</updated>

		<summary type="html">&lt;p&gt;Andy753421: /* Output */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This tutorial demonstrates how to use an Elphel (or perhaps another) camera to perform some basic computer vision tasks, such as identifying objects. For this example, we will be recognizing tennis balls.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
;OpenCV&lt;br /&gt;
:[http://opencv.willowgarage.com/wiki/ OpenCV] is a C library designed to help with computer vision programs. It provides quite a few useful functions that can save a lot typing when performing operations on images.&lt;br /&gt;
&lt;br /&gt;
;V4L/AVLD&lt;br /&gt;
:OpenCV provides a V4L API that can be used to acquire images from Elphel cameras. This is done using [[AVLD_-_Another_Video_Loopback_Device|AVLD]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Image acquisition ==&lt;br /&gt;
The first step is to get some images into OpenCV and display them. This assumes you have AVLD and V4L already set up. Below is a fairly minimal example that captures and displays images. It can be compiled with &#039;&#039;&#039;gcc -o main main.c $(pkg-config --libs --cflags opencv)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#include &amp;lt;opencv/cv.h&amp;gt;&lt;br /&gt;
#include &amp;lt;opencv/highgui.h&amp;gt;&lt;br /&gt;
#include &amp;lt;X11/keysym.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
int main(int argc, char **argv)&lt;br /&gt;
{&lt;br /&gt;
	/* Start the CV system and get the first v4l camera */&lt;br /&gt;
	cvInitSystem(argc, argv);&lt;br /&gt;
	CvCapture *cam = cvCreateCameraCapture(0);&lt;br /&gt;
&lt;br /&gt;
	/* Create a window to use for displaying the images */&lt;br /&gt;
	cvNamedWindow(&amp;quot;img&amp;quot;, 0);&lt;br /&gt;
	cvMoveWindow(&amp;quot;img&amp;quot;, 200, 200);&lt;br /&gt;
&lt;br /&gt;
	/* Display images until the user presses q */&lt;br /&gt;
	while (1) {&lt;br /&gt;
		cvGrabFrame(cam);&lt;br /&gt;
		IplImage *img = cvRetrieveFrame(cam);&lt;br /&gt;
		cvShowImage(&amp;quot;img&amp;quot;, img);&lt;br /&gt;
		if (cvWaitKey(10) == XK_q)&lt;br /&gt;
			return 0;&lt;br /&gt;
		cvReleaseImage(&amp;amp;img);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Processing ==&lt;br /&gt;
=== Color space ===&lt;br /&gt;
A good first step in many CV algorithms is to convert the image to HSV (or another similar color space). This make picking out objects based on colors a bit simpler as will be seen later. We&#039;ll make a copy of the original image so that we can display it at the end. Note that OpenCV stores images in BGR format by default.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	CvSize size = cvGetSize(img);&lt;br /&gt;
	IplImage *hsv = cvCreateImage(size, IPL_DEPTH_8U, 3);&lt;br /&gt;
	cvCvtColor(img, hsv, CV_BGR2HSV);  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Masks ===&lt;br /&gt;
The next step is to select all pixels that we think might be part of a tennis ball. We&#039;ll do this based purely on their HSV values. OpenCV provides a InRanage function that can be used  to pick out pixels based on their values. This generates a mask; a binary image where the foreground (white) pixels were with in the specified range. We&#039;re done with the HSV image after this, so we can free it&#039;s memory.&lt;br /&gt;
&lt;br /&gt;
Picking the ranges for creating mask is one of the more complicated parts of a CV algorithm. For now, manually tuning the values is easiest. You could also use a machine learning algorithm to pick the ranges automatically.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	CvMat *mask = cvCreateMat(size.height, size.width, CV_8UC1);&lt;br /&gt;
	cvInRangeS(hsv, cvScalar(0.11*256, 0.60*256, 0.20*256, 0),&lt;br /&gt;
	                cvScalar(0.14*256, 1.00*256, 1.00*256, 0), mask);&lt;br /&gt;
	cvReleaseImage(&amp;amp;hsv);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Morphological operations ===&lt;br /&gt;
No matter how good your ranges are when generating a mask, there will almost always be noise in the mask. In our example, the white lines on the tennis ball don&#039;t show up because they don&#039;t fit the hue range. Much of this nose can be eliminated by using a series of morphological operations. Two commonly uses operation are [http://en.wikipedia.org/wiki/Opening_(morphology) opening] and [http://en.wikipedia.org/wiki/Closing_(morphology) closing], which are in turn comprised of [http://en.wikipedia.org/wiki/Dilation_(morphology) dilate] and [http://en.wikipedia.org/wiki/Erosion_(morphology) erode] operations. The table below summarizes these operations.&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
! Operation !! Effect / Use&lt;br /&gt;
|-&lt;br /&gt;
| Dilate || Expand the foreground&lt;br /&gt;
|-&lt;br /&gt;
| Erode  || contract the foreground (~ expand background)&lt;br /&gt;
|-&lt;br /&gt;
| Close  || Dilation followed by erosion, removes specks of background, fills in foreground areas.&lt;br /&gt;
|-&lt;br /&gt;
| Open   || Erosion followed by dilation, removes specks of foreground, fills in background areas.&lt;br /&gt;
|} &lt;br /&gt;
&lt;br /&gt;
Morphological operations are performed with a [http://en.wikipedia.org/wiki/Structuring_element Structuring Element]. In computer vision, this is typically a oval or a rectangle of some specific size. Note that using rectangles results in faster code but can also cause poorer results.&lt;br /&gt;
&lt;br /&gt;
Below, we use a large rectangular structuring element along with a close to remove the black lines that show up in the tennis balls. Afterwards we perform an open with a smaller structuring element to eliminate some additional nose from the image.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	IplConvKernel *se21 = cvCreateStructuringElementEx(21, 21, 10, 10, CV_SHAPE_RECT, NULL);&lt;br /&gt;
	IplConvKernel *se11 = cvCreateStructuringElementEx(11, 11, 5,  5,  CV_SHAPE_RECT, NULL);&lt;br /&gt;
	cvClose(mask, mask, se21);&lt;br /&gt;
	cvOpen(mask, mask, se11);&lt;br /&gt;
	cvReleaseStructuringElement(&amp;amp;se21);&lt;br /&gt;
	cvReleaseStructuringElement(&amp;amp;se11);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Hough transform ===&lt;br /&gt;
The real work in finding tennis balls is done by a Hough transform. The specifics of this are beyond the scope of this tutorial. We&#039;ll just treat it as a black box function that finds circular objects in a gray input image.&lt;br /&gt;
&lt;br /&gt;
The OpenCV Hough function performs a Canny edge detection on the input image before doing running the actual Hough transform. Due to this and the way the Hough transform works, it is beneficial to do quite a bit of smoothing to get a nice gradient around the edge of the circles before passing the image to the Hough function. Many of the parameters to the Hough function can also be tuned to provide better results.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	/* Copy mask into a gray scale image */&lt;br /&gt;
	IplImage *hough_in = cvCreateImage(size, 8, 1);&lt;br /&gt;
	cvCopy(mask, hough_in, NULL);&lt;br /&gt;
        cvSmooth(hough_in, hough_in, CV_GAUSSIAN, 15, 15, 0, 0);&lt;br /&gt;
&lt;br /&gt;
	/* Run the Hough function */&lt;br /&gt;
	CvMemStorage *storage = cvCreateMemStorage(0);&lt;br /&gt;
	CvSeq *circles = cvHoughCircles(hough_in, storage,&lt;br /&gt;
		CV_HOUGH_GRADIENT, 4, size.height/10, 100, 40, 0, 0);&lt;br /&gt;
	cvReleaseMemStorage(&amp;amp;storage);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Output ==&lt;br /&gt;
The output of the Hough function can then be used in a variety of ways. For now we&#039;ll just draw some circles and centers onto the original input image before displaying it.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	int i;&lt;br /&gt;
	for (i = 0; i &amp;lt; circles-&amp;gt;total; i++) {&lt;br /&gt;
             float *p = (float*)cvGetSeqElem(circles, i);&lt;br /&gt;
	     CvPoint center = cvPoint(cvRound(p[0]),cvRound(p[1]));&lt;br /&gt;
	     CvScalar val = cvGet2D(mask, center.y, center.x);&lt;br /&gt;
	     if (val.val[0] &amp;lt; 1) continue;&lt;br /&gt;
             cvCircle(img,  center, 3,             CV_RGB(0,255,0), -1, CV_AA, 0);&lt;br /&gt;
             cvCircle(img,  center, cvRound(p[2]), CV_RGB(255,0,0),  3, CV_AA, 0);&lt;br /&gt;
             cvCircle(mask, center, 3,             CV_RGB(0,255,0), -1, CV_AA, 0);&lt;br /&gt;
             cvCircle(mask, center, cvRound(p[2]), CV_RGB(255,0,0),  3, CV_AA, 0);&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Acknowledgments ==&lt;/div&gt;</summary>
		<author><name>Andy753421</name></author>
	</entry>
	<entry>
		<id>https://wiki.elphel.com/index.php?title=OpenCV_Tennis_balls_recognizing_tutorial&amp;diff=6092</id>
		<title>OpenCV Tennis balls recognizing tutorial</title>
		<link rel="alternate" type="text/html" href="https://wiki.elphel.com/index.php?title=OpenCV_Tennis_balls_recognizing_tutorial&amp;diff=6092"/>
		<updated>2009-06-18T13:49:26Z</updated>

		<summary type="html">&lt;p&gt;Andy753421: /* Processing */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This tutorial demonstrates how to use an Elphel (or perhaps another) camera to perform some basic computer vision tasks, such as identifying objects. For this example, we will be recognizing tennis balls.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
;OpenCV&lt;br /&gt;
:[http://opencv.willowgarage.com/wiki/ OpenCV] is a C library designed to help with computer vision programs. It provides quite a few useful functions that can save a lot typing when performing operations on images.&lt;br /&gt;
&lt;br /&gt;
;V4L/AVLD&lt;br /&gt;
:OpenCV provides a V4L API that can be used to acquire images from Elphel cameras. This is done using [[AVLD_-_Another_Video_Loopback_Device|AVLD]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Image acquisition ==&lt;br /&gt;
The first step is to get some images into OpenCV and display them. This assumes you have AVLD and V4L already set up. Below is a fairly minimal example that captures and displays images. It can be compiled with &#039;&#039;&#039;gcc -o main main.c $(pkg-config --libs --cflags opencv)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#include &amp;lt;opencv/cv.h&amp;gt;&lt;br /&gt;
#include &amp;lt;opencv/highgui.h&amp;gt;&lt;br /&gt;
#include &amp;lt;X11/keysym.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
int main(int argc, char **argv)&lt;br /&gt;
{&lt;br /&gt;
	/* Start the CV system and get the first v4l camera */&lt;br /&gt;
	cvInitSystem(argc, argv);&lt;br /&gt;
	CvCapture *cam = cvCreateCameraCapture(0);&lt;br /&gt;
&lt;br /&gt;
	/* Create a window to use for displaying the images */&lt;br /&gt;
	cvNamedWindow(&amp;quot;img&amp;quot;, 0);&lt;br /&gt;
	cvMoveWindow(&amp;quot;img&amp;quot;, 200, 200);&lt;br /&gt;
&lt;br /&gt;
	/* Display images until the user presses q */&lt;br /&gt;
	while (1) {&lt;br /&gt;
		cvGrabFrame(cam);&lt;br /&gt;
		IplImage *img = cvRetrieveFrame(cam);&lt;br /&gt;
		cvShowImage(&amp;quot;img&amp;quot;, img);&lt;br /&gt;
		if (cvWaitKey(10) == XK_q)&lt;br /&gt;
			return 0;&lt;br /&gt;
		cvReleaseImage(&amp;amp;img);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Processing ==&lt;br /&gt;
=== Color space ===&lt;br /&gt;
A good first step in many CV algorithms is to convert the image to HSV (or another similar color space). This make picking out objects based on colors a bit simpler as will be seen later. We&#039;ll make a copy of the original image so that we can display it at the end. Note that OpenCV stores images in BGR format by default.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	CvSize size = cvGetSize(img);&lt;br /&gt;
	IplImage *hsv = cvCreateImage(size, IPL_DEPTH_8U, 3);&lt;br /&gt;
	cvCvtColor(img, hsv, CV_BGR2HSV);  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Masks ===&lt;br /&gt;
The next step is to select all pixels that we think might be part of a tennis ball. We&#039;ll do this based purely on their HSV values. OpenCV provides a InRanage function that can be used  to pick out pixels based on their values. This generates a mask; a binary image where the foreground (white) pixels were with in the specified range. We&#039;re done with the HSV image after this, so we can free it&#039;s memory.&lt;br /&gt;
&lt;br /&gt;
Picking the ranges for creating mask is one of the more complicated parts of a CV algorithm. For now, manually tuning the values is easiest. You could also use a machine learning algorithm to pick the ranges automatically.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	CvMat *mask = cvCreateMat(size.height, size.width, CV_8UC1);&lt;br /&gt;
	cvInRangeS(hsv, cvScalar(0.11*256, 0.60*256, 0.20*256, 0),&lt;br /&gt;
	                cvScalar(0.14*256, 1.00*256, 1.00*256, 0), mask);&lt;br /&gt;
	cvReleaseImage(&amp;amp;hsv);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Morphological operations ===&lt;br /&gt;
No matter how good your ranges are when generating a mask, there will almost always be noise in the mask. In our example, the white lines on the tennis ball don&#039;t show up because they don&#039;t fit the hue range. Much of this nose can be eliminated by using a series of morphological operations. Two commonly uses operation are [http://en.wikipedia.org/wiki/Opening_(morphology) opening] and [http://en.wikipedia.org/wiki/Closing_(morphology) closing], which are in turn comprised of [http://en.wikipedia.org/wiki/Dilation_(morphology) dilate] and [http://en.wikipedia.org/wiki/Erosion_(morphology) erode] operations. The table below summarizes these operations.&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
! Operation !! Effect / Use&lt;br /&gt;
|-&lt;br /&gt;
| Dilate || Expand the foreground&lt;br /&gt;
|-&lt;br /&gt;
| Erode  || contract the foreground (~ expand background)&lt;br /&gt;
|-&lt;br /&gt;
| Close  || Dilation followed by erosion, removes specks of background, fills in foreground areas.&lt;br /&gt;
|-&lt;br /&gt;
| Open   || Erosion followed by dilation, removes specks of foreground, fills in background areas.&lt;br /&gt;
|} &lt;br /&gt;
&lt;br /&gt;
Morphological operations are performed with a [http://en.wikipedia.org/wiki/Structuring_element Structuring Element]. In computer vision, this is typically a oval or a rectangle of some specific size. Note that using rectangles results in faster code but can also cause poorer results.&lt;br /&gt;
&lt;br /&gt;
Below, we use a large rectangular structuring element along with a close to remove the black lines that show up in the tennis balls. Afterwards we perform an open with a smaller structuring element to eliminate some additional nose from the image.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	IplConvKernel *se21 = cvCreateStructuringElementEx(21, 21, 10, 10, CV_SHAPE_RECT, NULL);&lt;br /&gt;
	IplConvKernel *se11 = cvCreateStructuringElementEx(11, 11, 5,  5,  CV_SHAPE_RECT, NULL);&lt;br /&gt;
	cvClose(mask, mask, se21);&lt;br /&gt;
	cvOpen(mask, mask, se11);&lt;br /&gt;
	cvReleaseStructuringElement(&amp;amp;se21);&lt;br /&gt;
	cvReleaseStructuringElement(&amp;amp;se11);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Hough transform ===&lt;br /&gt;
The real work in finding tennis balls is done by a Hough transform. The specifics of this are beyond the scope of this tutorial. We&#039;ll just treat it as a black box function that finds circular objects in a gray input image.&lt;br /&gt;
&lt;br /&gt;
The OpenCV Hough function performs a Canny edge detection on the input image before doing running the actual Hough transform. Due to this and the way the Hough transform works, it is beneficial to do quite a bit of smoothing to get a nice gradient around the edge of the circles before passing the image to the Hough function. Many of the parameters to the Hough function can also be tuned to provide better results.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	/* Copy mask into a gray scale image */&lt;br /&gt;
	IplImage *hough_in = cvCreateImage(size, 8, 1);&lt;br /&gt;
	cvCopy(mask, hough_in, NULL);&lt;br /&gt;
        cvSmooth(hough_in, hough_in, CV_GAUSSIAN, 15, 15, 0, 0);&lt;br /&gt;
&lt;br /&gt;
	/* Run the Hough function */&lt;br /&gt;
	CvMemStorage *storage = cvCreateMemStorage(0);&lt;br /&gt;
	CvSeq *circles = cvHoughCircles(hough_in, storage,&lt;br /&gt;
		CV_HOUGH_GRADIENT, 4, size.height/10, 100, 40, 0, 0);&lt;br /&gt;
	cvReleaseMemStorage(&amp;amp;storage);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Output ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Acknowledgments ==&lt;/div&gt;</summary>
		<author><name>Andy753421</name></author>
	</entry>
	<entry>
		<id>https://wiki.elphel.com/index.php?title=OpenCV_Tennis_balls_recognizing_tutorial&amp;diff=6091</id>
		<title>OpenCV Tennis balls recognizing tutorial</title>
		<link rel="alternate" type="text/html" href="https://wiki.elphel.com/index.php?title=OpenCV_Tennis_balls_recognizing_tutorial&amp;diff=6091"/>
		<updated>2009-06-18T13:06:13Z</updated>

		<summary type="html">&lt;p&gt;Andy753421: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This tutorial demonstrates how to use an Elphel (or perhaps another) camera to perform some basic computer vision tasks, such as identifying objects. For this example, we will be recognizing tennis balls.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
;OpenCV&lt;br /&gt;
:[http://opencv.willowgarage.com/wiki/ OpenCV] is a C library designed to help with computer vision programs. It provides quite a few useful functions that can save a lot typing when performing operations on images.&lt;br /&gt;
&lt;br /&gt;
;V4L/AVLD&lt;br /&gt;
:OpenCV provides a V4L API that can be used to acquire images from Elphel cameras. This is done using [[AVLD_-_Another_Video_Loopback_Device|AVLD]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Image acquisition ==&lt;br /&gt;
The first step is to get some images into OpenCV and display them. This assumes you have AVLD and V4L already set up. Below is a fairly minimal example that captures and displays images. It can be compiled with &#039;&#039;&#039;gcc -o main main.c $(pkg-config --libs --cflags opencv)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#include &amp;lt;opencv/cv.h&amp;gt;&lt;br /&gt;
#include &amp;lt;opencv/highgui.h&amp;gt;&lt;br /&gt;
#include &amp;lt;X11/keysym.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
int main(int argc, char **argv)&lt;br /&gt;
{&lt;br /&gt;
	/* Start the CV system and get the first v4l camera */&lt;br /&gt;
	cvInitSystem(argc, argv);&lt;br /&gt;
	CvCapture *cam = cvCreateCameraCapture(0);&lt;br /&gt;
&lt;br /&gt;
	/* Create a window to use for displaying the images */&lt;br /&gt;
	cvNamedWindow(&amp;quot;img&amp;quot;, 0);&lt;br /&gt;
	cvMoveWindow(&amp;quot;img&amp;quot;, 200, 200);&lt;br /&gt;
&lt;br /&gt;
	/* Display images until the user presses q */&lt;br /&gt;
	while (1) {&lt;br /&gt;
		cvGrabFrame(cam);&lt;br /&gt;
		IplImage *img = cvRetrieveFrame(cam);&lt;br /&gt;
		cvShowImage(&amp;quot;img&amp;quot;, img);&lt;br /&gt;
		if (cvWaitKey(10) == XK_q)&lt;br /&gt;
			return 0;&lt;br /&gt;
		cvReleaseImage(&amp;amp;img);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Processing ==&lt;br /&gt;
=== Color space ===&lt;br /&gt;
=== Masks ===&lt;br /&gt;
=== Morphological operations ===&lt;br /&gt;
=== Hough transform ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Output ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Acknowledgments ==&lt;/div&gt;</summary>
		<author><name>Andy753421</name></author>
	</entry>
	<entry>
		<id>https://wiki.elphel.com/index.php?title=OpenCV_Tennis_balls_recognizing_tutorial&amp;diff=6090</id>
		<title>OpenCV Tennis balls recognizing tutorial</title>
		<link rel="alternate" type="text/html" href="https://wiki.elphel.com/index.php?title=OpenCV_Tennis_balls_recognizing_tutorial&amp;diff=6090"/>
		<updated>2009-06-18T12:42:03Z</updated>

		<summary type="html">&lt;p&gt;Andy753421: templating some things out&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This tutorial demonstrates how to use an Elphel (or perhaps another) camera to perform some basic computer vision tasks, such as identifying objects. For this example, we will be recognizing tennis balls.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
=== OpenCV ===&lt;br /&gt;
=== V4L/AVLD ===&lt;br /&gt;
&lt;br /&gt;
== Image acquisition ==&lt;br /&gt;
&lt;br /&gt;
== Processing ==&lt;br /&gt;
=== Color space ===&lt;br /&gt;
=== Masks ===&lt;br /&gt;
=== Morphological operations ===&lt;br /&gt;
=== Hough transform ===&lt;br /&gt;
&lt;br /&gt;
== Output ==&lt;br /&gt;
&lt;br /&gt;
== Acknowledgments ==&lt;/div&gt;</summary>
		<author><name>Andy753421</name></author>
	</entry>
	<entry>
		<id>https://wiki.elphel.com/index.php?title=Rose-Hulman_Robotics_Team&amp;diff=3534</id>
		<title>Rose-Hulman Robotics Team</title>
		<link rel="alternate" type="text/html" href="https://wiki.elphel.com/index.php?title=Rose-Hulman_Robotics_Team&amp;diff=3534"/>
		<updated>2008-10-23T01:37:09Z</updated>

		<summary type="html">&lt;p&gt;Andy753421: Updating with information for our net website&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The [http://rhitrobotics.org Rose-Hulman Robotics Team] is in the process of constructing an autonomous ground vehicle and will be competing in the [http://www.igvc.org IGVC] competition. We attended the competition during the summer of 2008 but were unable to compete due issues with our motor controllers. We plan on attending the 2009 competition this coming year and expect to do better.&lt;br /&gt;
&lt;br /&gt;
All of our software, hardware, and electronics designs are licensed under the GNU GPLv3 and are available from our [https://rhitrobotics.org/svn/rhrt/trunk/ subversion server]. Documentation is provided on our Trac development site. If you are interested in helping with our code please contact one us and we can set up a user account so that you can have write access out our systems.&lt;br /&gt;
&lt;br /&gt;
== Contact ==&lt;br /&gt;
* Our primary communication mechanism is our Trac website, see External Links below.&lt;br /&gt;
* We also regularly converse on [http://rhitrobotics.org/wiki/irc IRC] in #rhrt on irc.freenode.net&lt;br /&gt;
* We also maintain a [http://mailman.rose-hulman.edu/mailman/listinfo/arc mailing list], but this is primarily used for meeting reminders.&lt;br /&gt;
&lt;br /&gt;
== External Links ==&lt;br /&gt;
* http://rhitrobotics.org/ - Main development site based on Trac&lt;br /&gt;
* http://rhitrobotics.org/wiki/igvc - Wiki page for our efforts on the IGVC&lt;br /&gt;
* http://rhitrobotics.org/browser/trunk - Subversion browser for our codebase&lt;br /&gt;
** http://rhitrobotics.org/browser/trunk/software/rb/camera/elphel.py - Code to access Elphel 353 cameras&lt;br /&gt;
** http://rhitrobotics.org/browser/trunk/software/rb/vision - Image processing routines&lt;br /&gt;
* http://rhitrobotics.org/report/14 - Active tickets, organized by component.&lt;/div&gt;</summary>
		<author><name>Andy753421</name></author>
	</entry>
	<entry>
		<id>https://wiki.elphel.com/index.php?title=Rose-Hulman_Robotics_Team&amp;diff=3532</id>
		<title>Rose-Hulman Robotics Team</title>
		<link rel="alternate" type="text/html" href="https://wiki.elphel.com/index.php?title=Rose-Hulman_Robotics_Team&amp;diff=3532"/>
		<updated>2008-02-14T05:50:14Z</updated>

		<summary type="html">&lt;p&gt;Andy753421: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The [http://rhitrobotics.org Rose-Hulman Robotics Team] is in the process of constructing an autonomous ground vehicle and will be competing in the [http://www.igvc.org IGVC] competition.&lt;br /&gt;
&lt;br /&gt;
We are currently in the process of making our internal documentation available to the public. Currently read-only access is provided to anonymous users. If you are interested in helping contact one us and we can set up a user account so that you can make changes.&lt;br /&gt;
&lt;br /&gt;
== External Links ==&lt;br /&gt;
* https://rhitrobotics.org/ - &amp;quot;External&amp;quot; site, aimed at the general public&lt;br /&gt;
* https://project.rhitrobotics.org/wiki/ - Main development site/wiki&lt;br /&gt;
* https://project.rhitrobotics.org/trac/rt/ - Trac install for the software team&lt;br /&gt;
* https://project.rhitrobotics.org/svn/software/ - SVN repository used by the software team&lt;/div&gt;</summary>
		<author><name>Andy753421</name></author>
	</entry>
	<entry>
		<id>https://wiki.elphel.com/index.php?title=Rose-Hulman_Robotics_Team&amp;diff=3531</id>
		<title>Rose-Hulman Robotics Team</title>
		<link rel="alternate" type="text/html" href="https://wiki.elphel.com/index.php?title=Rose-Hulman_Robotics_Team&amp;diff=3531"/>
		<updated>2008-01-31T08:02:43Z</updated>

		<summary type="html">&lt;p&gt;Andy753421: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The [http://rhitrobotics.org Rose-Hulman Robotics Team] is in the process of constructing an autonomous ground vehicle and will be competing in the [http://www.igvc.org IGVC] competition.&lt;/div&gt;</summary>
		<author><name>Andy753421</name></author>
	</entry>
	<entry>
		<id>https://wiki.elphel.com/index.php?title=UserProjects&amp;diff=2130</id>
		<title>UserProjects</title>
		<link rel="alternate" type="text/html" href="https://wiki.elphel.com/index.php?title=UserProjects&amp;diff=2130"/>
		<updated>2008-01-31T07:53:25Z</updated>

		<summary type="html">&lt;p&gt;Andy753421: adding rhitrobotics link&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Research Projects  ==&lt;br /&gt;
There are several research and educational projects that use Elphel cameras. Some are already active, others just starting or only in planning stage. We believe that scientific research is the application area where the open nature of our products is the most beneficial. The shortage of the powerful and at the same time open and flexible hardware was that &amp;quot;itch&amp;quot; that led me to start Elphel.&lt;br /&gt;
&lt;br /&gt;
This page is started to provide resources to those who already uses or plans to use Elphel cameras. This is wiki, so please feel free to add you project description/link below.--[[User:Andrey.filippov|Andrey.filippov]] 14:59, 29 April 2007 (CDT)&lt;br /&gt;
&lt;br /&gt;
=== [[SCINI: Submersible Capable of under Ice Navigation and Imaging]] ===&lt;br /&gt;
&lt;br /&gt;
=== [[EPFL: Auto focus System]] ===&lt;br /&gt;
&lt;br /&gt;
=== [[Rose-Hulman Robotics Team]] ===&lt;/div&gt;</summary>
		<author><name>Andy753421</name></author>
	</entry>
</feed>