检测图像上的硬币(和椭圆形)

检测图像上的硬币(和椭圆形),第1张

检测图像上的硬币(和椭圆形)

这是一些实现传统方法(基于OpenCV doco)的C99源代码:

#include "cv.h"#include "highgui.h"#include <stdio.h>#ifndef M_PI#define M_PI 3.14159265358979323846#endif//// We need this to be high enough to get rid of things that are too small too// have a definite shape.  Otherwise, they will end up as ellipse false positives.//#define MIN_AREA 100.00    //// One way to tell if an object is an ellipse is to look at the relationship// of its area to its dimensions.  If its actual occupied area can be estimated// using the well-known area formula Area = PI*A*B, then it has a good chance of// being an ellipse.//// This value is the maximum permissible error between actual and estimated area.//#define MAX_TOL  100.00int main( int argc, char** argv ){    IplImage* src;    // the first command line parameter must be file name of binary (black-n-white) image    if( argc == 2 && (src=cvLoadImage(argv[1], 0))!= 0)    {        IplImage* dst  = cvCreateImage( cvGetSize(src), 8, 3 );        CvMemStorage* storage = cvCreateMemStorage(0);        CvSeq* contour = 0; cvThreshold( src, src, 1, 255, CV_THRESH_BINARY );        //        // Invert the image such that white is foreground, black is background.        // Dilate to get rid of noise.        //        cvXorS(src, cvScalar(255, 0, 0, 0), src, NULL);        cvDilate(src, src, NULL, 2); cvFindContours( src, storage, &contour, sizeof(CvContour), CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0));        cvZero( dst );        for( ; contour != 0; contour = contour->h_next )        { double actual_area = fabs(cvContourArea(contour, CV_WHOLE_SEQ, 0)); if (actual_area < MIN_AREA)     continue; // // FIXME: // Assuming the axes of the ellipse are vertical/perpendicular. // CvRect rect = ((CvContour *)contour)->rect; int A = rect.width / 2;  int B = rect.height / 2; double estimated_area = M_PI * A * B; double error = fabs(actual_area - estimated_area);     if (error > MAX_TOL)     continue;     printf (      "center x: %d y: %d A: %d B: %dn",      rect.x + A,      rect.y + B,      A,      B ); CvScalar color = CV_RGB( rand() % 255, rand() % 255, rand() % 255 ); cvDrawContours( dst, contour, color, color, -1, CV_FILLED, 8, cvPoint(0,0));        }        cvSaveImage("coins.png", dst, 0);    }}

给定Carnieri提供的二进制映像,这是输出:

./opencv-contour.out coin-ohtsu.pbmcenter x: 291 y: 328 A: 54 B: 42center x: 286 y: 225 A: 46 B: 32center x: 471 y: 221 A: 48 B: 33center x: 140 y: 210 A: 42 B: 28center x: 419 y: 116 A: 32 B: 19

这是输出图像:

硬币

您可以改善的地方:

处理不同的椭圆方向(当前,我假设轴是垂直/水平的)。使用图像矩将不难做到。
检查对象的凸度(看一下cvConvexityDefects)
区分硬币和其他物体的最佳方法可能是通过形状。我无法想到其他任何低级图像功能(颜色显然不可用)。因此,我可以想到两种方法:

传统物体检测
您的第一个任务是从背景中分离对象(硬币和非硬币)。如Carnieri所建议的,Ohtsu的方法将在这里很好地工作。您似乎担心图像是两部分的,但我认为这不会成为问题。只要可以看到大量办公桌,就可以保证直方图中有一个峰值。只要桌子上有几个视觉上可区分的物体,就可以确保您达到第二个高峰。

扩展您的二进制图像几次,以消除阈值留下的噪声。硬币相对较大,因此它们应能经受这种形态学 *** 作。

使用区域增长将白色像素分组为对象-只是迭代地连接相邻的前景像素。在此 *** 作结束时,您将获得不相交对象的列表,并且将知道每个对象占用哪些像素。

根据此信息,您将知道对象的宽度和高度(从上一步开始)。因此,现在您可以估计围绕对象的椭圆的大小,然后查看此特定对象与椭圆的匹配程度。仅使用宽度与高度之比可能会更容易。

另外,您也可以使用力矩以更精确的方式确定物体的形状。



欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/4945639.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-11-13
下一篇 2022-11-13

发表评论

登录后才能评论

评论列表(0条)

保存