当前位置: 首页 > 面试题库 >

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

程天佑
2023-03-14
问题内容

我目前正在一个项目中,尝试检测位于平面(即桌子)上的几枚硬币。硬币不会重叠,也不会被其他物体隐藏。但是,可能还有其他物体可见,并且照明条件可能并不完美…基本上,请考虑一下自己拍摄的桌子上放着一些硬币。

因此,每个点都应显示为椭圆形。由于我不知道相机的位置,椭圆的形状可能会有所不同,从圆形(从顶部看)到平坦的椭圆,具体取决于硬币拍摄的角度。

我的问题是我不确定如何提取硬币并最终将椭圆装在硬币上(我正在寻找进行进一步的计算)。

现在,我刚刚通过在OpenCV中设置阈值,使用findContours()获取轮廓线并拟合椭圆进行了首次尝试。不幸的是,轮廓线很少能给我硬币的形状(反射,光线不足等),而且由于我不想用户设置任何阈值,因此也不优选这种方式。

另一个想法是在该图像上使用椭圆的模板匹配方法,但是由于我既不知道相机的角度也不知道椭圆的大小,所以我认为这不太好…

所以我想问问是否有人可以告诉我一种适用于我的情况的方法。

有没有一种快速的方法可以从图像中提取三个硬币?计算应该在移动设备上实时进行,并且该方法对于不同的或变化的灯光或背景颜色不应太敏感。

如果有人可以给我提示哪种方法适合我的方法,那就太好了。


问题答案:

这是一些实现传统方法(基于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.00

int 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: %d\n",
                 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.pbm
center x: 291 y: 328 A: 54 B: 42
center x: 286 y: 225 A: 46 B: 32
center x: 471 y: 221 A: 48 B: 33
center x: 140 y: 210 A: 42 B: 28
center x: 419 y: 116 A: 32 B: 19

这是输出图像:

硬币

您可以改善的地方:

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

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

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

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

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

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



 类似资料:
  • 问题内容: 我想使用OpenCV 2.4.1软件包随附的Tutorial 2-Basic作为起点,使用Android版OpenCV检测椭圆。请注意,我的椭圆将是一个完美的photoshop之一。 据我了解,使用“ HoughCircles”只会找到完美的(或大约)圆,因此省略了椭圆。 任何帮助将不胜感激,因为我是OpenCV的初学者 到目前为止,这是我尝试过的 如果您认为更多信息可能有用,请告诉我

  • 基础示例 <vuep template="#example"></vuep> <script v-pre type="text/x-template" id="example"> <template> <div class="amap-page-container"> <el-amap vid="amapDemo" :zoom="zoom" :center="c

  • SVG 椭圆 - <ellipse> 实例 1 <ellipse> 元素是用来创建一个椭圆: 椭圆与圆很相似。不同之处在于椭圆有不同的x和y半径,而圆的x和y半径是相同的: 下面是SVG代码:<svg xmlns="http://www.w3.org/2000/svg" version="1.1"> <ellipse cx="300" cy="80" rx="100" ry="50" style=

  • 我试图通过OpenCV(Python)的图像预处理技术来检测黑白足球。我的想法如下; 处理图像(例如模糊的二进制照片) 找到多个候选足球(例如通过轮廓检测) 调整这些候选者的大小(例如48x48px),并在一个非常简单的神经网络中输入其像素对应的布尔值(0=黑色像素,1=白色像素),然后为每个候选者输出置信度值 确定足球是否存在于照片中,以及球的最可能位置 我一直在寻找合适的候选人。目前,这是我的

  • 主要内容:圆角矩形,椭圆示例JavaFX Shape类定义了常见的形状,例如线,矩形,圆,Arc,CubicCurve,Ellipse和QuadCurve。 在场景图上绘制矩形需要宽度,高度和左上角的(,)位置。 要在JavaFX中绘制一个矩形,可以使用类。 上面的代码生成以下结果。 圆角矩形 类实现了弧宽和弧高。可以使用这些功能来绘制圆角矩形。 上面的代码生成以下结果。 椭圆示例 上面的代码生成以下结果。

  • 问题内容: 请提供有关如何在椭圆形或圆形上进行裁剪的想法。请分享您的想法。 问题答案: 通过增加半径,它将变得更圆滑。 只要图像是正方形,就可以通过将宽度的一半作为拐角半径来获得一个完美的圆: 您还需要添加 斯威夫特4.2