当前位置: 首页 > 知识库问答 >
问题:

除了哈尔级联之外,还有哪些算法或方法可以用于自定义对象检测?

宗政博
2023-03-14

我需要做计算机视觉任务,以便检测瓦特瓶或汽水罐。我将获得瓶子、汽水罐或任何其他随机物体的“正面”图像(一个接一个),我的算法应该确定它是瓶子、罐还是其中任何一个。

有关对象检测场景的一些详细信息:

  • 如前所述,我将测试每个图像/视频帧的单个对象。
  • 并非所有的瓦特瓶都是一样的。塑料、盖子或标签可能会有颜色变化。也许有些不能得到标签或盖子。
  • 汽水罐的变化也一样。不过没有皱巴巴的汽水罐会被测试。
  • 物体之间可能存在微小的尺寸差异。
  • 我可以有一个绿色(或任何自定义颜色)的背景。
  • 我会对图像做任何需要的过滤。
  • 这将在树莓派上运行。

为了以防万一,请举一个例子:

我已经测试了几次OpenCV人脸检测算法,我知道它工作得很好,但是我需要获得一个特殊的哈尔级联特征XML文件来检测这种方法上的每个自定义对象。

因此,我心中的不同选择是:

  • 创建自定义哈尔分类器。
  • 考虑形状。
  • 考虑到轮廓。

我想得到一个简单的算法,我认为甚至不需要创建一个定制的Haar分类器。你有什么建议?

我强烈考虑了形状/长宽比方法。

然而,我想我面临着一些问题,因为瓶子有不同的尺寸甚至形状。但这让我思考或设定了以下考虑:

  • 我用THRESH_二元法设置了一个阈值。(多亏了答案)

我所取得的成就:

Threshold真的帮了我的忙,我注意到在白色背景测试中,我会获得罐头:

这就是瓶子所得到的:

所以,留下优势的较暗区域是明显的。在罐头中有一些情况下,这可能会变成假阴性。对于瓶子来说,光线和角度可能会导致不一致的结果,但我真的认为这可能是一个更短的方法。

所以,我现在很困惑我应该如何评估这种黑暗主导,我读到了findContours导致了它,但我对如何抓住这种功能非常迷茫。例如,在汽水罐的情况下,它可能会找到几个轮廓,所以我不知道该评估什么。

注意:我愿意测试与open CV不同的任何其他算法或库。

共有3个答案

长孙嘉容
2023-03-14

正如cyriel所建议的,纵横比(宽度/高度)可能是一个有用的指标。下面是一些OpenCV Python代码,可以找到轮廓(希望包括瓶子或罐子的轮廓),并提供纵横比和其他一些度量:

    # src image should have already had some contrast enhancement (such as
    # cv2.threshold) and edge finding (such as cv2.Canny)
    contours, hierarchy = cv2.findContours(src, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    for contour in contours:
    num_points = len(contour)
    if num_points < 5:
        # The contour has too few points to fit an ellipse. Skip it.
        continue

    # We could use area to help determine the type of object.
    # Small contours are probably false detections (not really a whole object).
    area = cv2.contourArea(contour)

    bounding_ellipse = cv2.fitEllipse(contour)
    center, radii, angle_degrees = bounding_ellipse

    # Let's define an ellipse's normal orientation to be landscape (width > height).
    # We must ensure that the ellipse's measurements match this orientation.
    if radii[0] < radii[1]:
        radii = (radii[1], radii[0])
        angle_degrees -= 90.0

    # We could use the angle to help determine the type of object.
    # A bottle or can's angle is probably approximately a multiple of 90 degrees,
    # assuming that it is at rest and not falling.

    # Calculate the aspect ratio (width / height).
    # For example, 0.5 means the object's height is 2 times its width.
    # A bottle is probably taller than a can.
    aspect_ratio = radii[0] / radii[1]

为了检查透明度,您可以使用直方图分析或背景减法将图片与已知背景进行比较。

轮廓的力矩可用于确定其质心(重心):

    moments = cv2.moments(contour)
    m00 = moments['m00']
    m01 = moments['m01']
    m10 = moments['m10']
    centroid = (m10 / m00, m01 / m00)

你可以把它比作中心。如果物体的一端更大(“更重”),形心就会比中心更靠近那一端。

弘承业
2023-03-14

因为你想识别罐头和瓶子,而不是百事可乐和可口可乐,所以与Haar和SIFT/SURF/ORB等2D匹配功能相比,形状匹配可能是一种选择

独特的背景颜色会让事情变得更容易。

首先,仅从背景图像创建直方图

int channels[] = {0,1,2}; // use all the channels
int rgb_bins = 32; // quantize to 32 colors per channel
int histSize[] = {rgb_bins, rgb_bins, rgb_bins};
float _range[] = {0,255};
float* ranges[] = {_range, _range, _range};

cv::SparseMat bghist;
cv::calcHist(&bg_image, 1, channels, cv::noArray(),bghist, 3, histSize, ranges );

然后使用calcBackProject创建bg而不是bg的掩码

cv::MatND temp_ND;
cv::calcBackProject( &bottle_image, 1, channels, bghist, temp_ND, ranges );

cv::Mat bottle_mask, bottle_backproj;
if( feeling_lazy ){
    cv::normalize(temp_ND, bottle_backproj, 0, 255, cv::NORM_MINMAX, CV_8U);
    //a small blur here could work nicely
    threshold( bottle_backproj, bottle_mask, 0, 255, THRESH_OTSU );
    bottle_mask = cv::Scalar(255) - bottle_mask; //invert the mask
} else {
    //finding just the right value here might be better than the above method
    int magic_threshold = 64; 
    temp_ND.convertTo( bottle_backproj, CV_8U, 255.); 
    //I expect temp_ND to be CV_32F ranging from 0-1, but I might be wrong.
    threshold( bottle_backproj, bottle_mask, magic_threshold, 255, THRESH_BINARY_INV );
}

然后:

使用带有置信度阈值的matchTemplate,将bottle_mask或bottle_backproj与几个样本bottle mask/backproj进行比较,以确定是否匹配。

matchTemplate(bottle_mask, bottle_template, result, CV_TM_CCORR_NORMED);
double confidence; minMaxLoc( result, NULL, &confidence);

或者使用matchShapes,尽管我从来没有让它正常工作过。

double confidence = matchShapes(bottle_mask, bottle_template, CV_CONTOURS_MATCH_I3);

或者使用linemod,这很难设置,但对于形状不太复杂的图像效果很好。除了链接的文件之外,我还没有找到这种方法的任何工作示例,所以下面是我所做的。

首先使用一些示例图像创建/训练检测器

//some magic numbers
std::vector<int> T_at_level;
T_at_level.push_back(4); 
T_at_level.push_back(8);

//add some padding so linemod doesn't scream at you
const int T = 32;
int width = bottle_mask.cols;
if( width % T != 0)
    width += T - width % T;

int height = bottle_mask.rows;
if( height % T != 0)
    height += T - height % T;

//in this case template_backproj is created specifically from a sample bottle_backproj
cv::Rect padded_roi( (width - template_backproj.cols)/2, (height - template_backproj.rows)/2, template_backproj.cols, template_backproj.rows);
cv::Mat padded_backproj = zeros( width, height, template_backproj.type());
padded_backproj( padded_roi ) = template_backproj;

cv::Mat padded_mask = zeros( width, height, template_mask.type());
padded_mask( padded_roi ) = template_mask; 
//you might need to erode padded_mask by a few pixels.

//initialize detector
std::vector< cv::Ptr<cv::linemod::Modality> > modalities;
modalities.push_back( cv::makePtr<cv::linemod::ColorGradient>() ); //for those that don't have a kinect
cv::Ptr<cv::linemod::Detector> new_detector = cv::makePtr<cv::linemod::Detector>(modalities, T_at_level);

//add sample images to the detector
std::vector<cv::Mat> template_images;
templates.push_back( padded_backproj);
cv::Rect ignore_me;
const std::string class_id = "bottle";
template_id = new_detector->addTemplate(template_images, class_id, padded_mask, &ignore_me);

然后进行匹配

std::vector<cv::Mat> sources_vec;
sources_vec.push_back( padded_backproj );
//padded_backproj doesn't need to be the same size as the trained template images, but it does need to be padded the same way.
float matching_threshold = 0.8; //a higher number makes the algorithm faster
std::vector<cv::linemod::Match> matches;
std::vector<cv::String> class_ids;

new_detector->match(sources_vec, matching_threshold, matches,class_ids);
float confidence = matches.size() > 0? matches[0].similarity : 0;
东郭赞
2023-03-14

我在这里看到一些基本的想法:

  1. 检查对象(准确地说是对象边界矩形)的宽/高比。对于罐头来说大约是2-2.5,对于瓶子我想应该是
 类似资料:
  • 问题内容: 为什么没有人提及嵌套循环联接? 问题答案: 如果希望/可以读取未提交的记录,则在联接上使用(NOLOCK)可能会提高性能。 什么时候应该使用“with(nolock)”

  • 请求对象{ 现场1:-444-44444-4444-4444-44444444; 场域2:-1234; 我想验证这些字段,

  • 我在spring data jpa中的自定义删除方法中遇到错误。基本上,有一个包包含物品,当删除该包时,应该删除其中的所有物品。 以下是实体: 和存储库: 当我调用BagRepository.deleteByUidAndName(uid, name)时,我从hibernate中得到一个与外键约束相关的异常。设置显示它在删除包之前不会尝试先删除项目。 然而,如果我调用然后一切正常。 我想知道自定义这

  • 问题内容: 我需要在Python中创建一个“容器”对象或类,以记录我也定义的其他对象。此容器的一项要求是,如果两个对象被视为相同,则将一个(一个)删除。我的第一个想法是使用a作为包含对象,以完成此要求。 但是,该集合不会删除两个相同的对象实例之一。我必须定义什么才能创建一个? 这是Python代码。 口译员 显然,由调用的不是集合所调用的方法。叫什么 我还必须定义什么其他方法? 注意: s必须保持

  • 问题内容: 我记得在Java书籍中读过有关“ instanceof”以外的任何运算符的信息,用于比较两个对象之间的类型层次结构。 instanceof是最常用和最常用的。我无法清楚地记得是否确实存在另一种方式。 问题答案: 就在这里。不是运算符,而是Class类上的方法。 它是: isIntance(Object o) 从文档引用: …此方法是Java语言instanceof运算符的动态等效项

  • 问题内容: 我有一个包装两栏式布局的古老问题。我的侧边栏处于浮动状态,因此我的容器无法包装内容和侧边栏。 似乎有许多方法可以解决Firefox中的明显错误: 在我的情况下,似乎唯一可以正常工作的解决方案是解决方案,这有点麻烦。给我带来讨厌的滚动条,并且肯定有副作用。另外,由于它的不正确行为,IE7显然不应该遭受此问题的困扰,但就我而言,它与Firefox一样遭受痛苦。 我们目前可以使用哪种方法最可