Find image within image (object detection)
我确实有不同的图像,它们都在"真实"图像周围有某种边界。我想实现的是找到"真实"的图像(以像素为单位的大小和位置)。
对我来说,挑战在于边界并不总是黑色的(可以是任何一种有很多噪音的黑色或灰色),而"真实"图像(本例中的鲨鱼水)可以有任何颜色、饱和度等组合。
现在一般来说,我知道一些算法,比如canny、blob检测、hough行等等,但我刚刚开始使用它们。到目前为止,我设法找到了一个特定图像的边界,但一旦我尝试对下一个图像应用相同的算法和参数,它就不起作用了。我当前的方法如下(伪代码):
转换为灰色CvInvoke.CvtColor(_processedImage, tempMat, CvEnum.ColorConversion.Rgb2Gray)。
使用CvInvoke.PyrDown(srcImage, targetImage)和CvInvoke.PyrUp(srcImage, targetImage)进行降采样
用CvInvoke.GaussianBlur(_processedImage, bluredImage, New Drawing.Size(5, 5), 0)模糊图像
用CvInvoke.Threshold(_processedImage, blackWhiteImage, _parameters.BinarizeThreshold, 255, CvEnum.ThresholdType.Binary)二值化
用CvInvoke.Canny(_processedImage, imgEdges, 60, 100)检测边缘
使用'cvinvoke.find contours'查找轮廓(_processedimage,contours,nothing,cvenum.retrtype.external,cvenum.chainApprovxMethod.chainApprovxSimple)
假设最大轮廓是真实图像
我已经尝试了不同的方法,例如:
任何提示,特别是如何找到合适的参数(适用于所有图像)的算法,如(自适应)阈值和精明,以及改善处理管道的想法,都将受到高度赞赏。
如果边界是统一的,那就很容易了。使用cv::reduce查找每行和每列的最小值和最大值,然后计算其最小值和最大值与附近角的像素值相等(或非常接近)的顶部、左侧、底部、右侧行/列。为了保持头脑清醒,可能要检查边框的颜色是否各不相同。
在您的示例中,边框包含微弱的红色内容,但行/列方法可能仍然是简化问题的一种有用方法。也许,正如诺法尔所建议的,用你认为是背景色的颜色来做一个绝对的区别;将它平方,转换成灰色,然后减少到行和列的总和。您仍然需要查找边,但已将数据从二维缩减为一维。
如果有一个大的边界和大量的噪声,可以迭代:在第二遍中,从列的统计信息中排除您认为构成边界的行(反之亦然)。
编辑:以上仅适用于垂直矩形!如果可以旋转,则行/列投影方法将无法工作。在这种情况下,我可能会像上面那样求平方差之和(不要先转换为灰色,因为它可能会丢弃信息),然后是模糊或某些形态,边缘检测,然后是某种hough转换,以找到直边。
- 好主意!谢谢。实际上,矩形是轻微旋转的。刚刚研究了平方差之和。但是,我不清楚如何在单个图像上使用它。我可以假设整体图像的某一部分将是边界。这就是你的意思吗?或者你是在考虑更细的纹理,并将图像的某些部分相互比较?
- @我没有一个完整的解决方案,但我试图提出一些想法。最终,这将取决于你的具体形象内容。如果旋转很小,我可能仍然会从切断行和列开始。是否有任何区域始终为背景;或者背景始终为深色?如果没有,那么您可能需要其他方法来识别背景,例如其纹理。(看起来像是一部电影,在这种情况下,你也可以用多帧来做一些事情…)
- 非常感谢您的时间和努力!下周我一回到我的机器上就会检查你的想法。
您可以尝试从该图像中减去黑色图像,然后获得内部图像,方法如下:使用图像减法比较C中的图像,
- 谢谢你的想法和链接。我是否正确地理解了这一点,即我从一个完全黑色的图像开始,然后是我的原始图像,然后从黑色中减去原始图像?正如问题中提到的,边界并不总是黑色的,而是一种灰色。所以我会以另一种灰色的边界结束,对吗?下一个问题是我需要内部图像的坐标和大小。怎么做?对于初学者的问题我很抱歉,但我真的不太清楚。
- 减去一个完全黑色的图像当然是一个禁忌,但减去其他东西可能是有用的。btw opencv有一个内置的函数来计算图像之间的绝对差异,并找到最大值。