opencv图像中目标区域的检测 我们目前正在尝试使用OpenCV、C++版本中的方法来检测医疗仪器图像中的对象区域。示例图像如下所示:
以下是我们将遵循的步骤:opencv图像中目标区域的检测 我们目前正在尝试使用OpenCV、C++版本中的方法来检测医疗仪器图像中的对象区域。示例图像如下所示: ,opencv,cluster-analysis,object-detection,connected-components,Opencv,Cluster Analysis,Object Detection,Connected Components,以下是我们将遵循的步骤: 将图像转换为灰度 中值滤波的应用 使用sobel过滤器查找边 使用25的阈值将结果转换为二值图像 对图像进行骨架化,以确保边缘整洁 求X最大连通分量 此方法适用于图像1,结果如下: 黄色边框是检测到的连接组件 矩形只是为了突出显示连接组件的存在 为了获得可理解的结果,我们只需删除完全位于任何其他组件内部的连接组件,因此最终结果如下: 到目前为止,一切都很好,但另一个图像样本使我们的工作变得复杂,如下所示。 将一条浅绿色的小毛巾放在物体下面会产生以下图像:
- 将图像转换为灰度
- 中值滤波的应用
- 使用sobel过滤器查找边
- 使用25的阈值将结果转换为二值图像
- 对图像进行骨架化,以确保边缘整洁
- 求X最大连通分量
1
,结果如下:
- 黄色边框是检测到的连接组件
- 矩形只是为了突出显示连接组件的存在
- 为了获得可理解的结果,我们只需删除完全位于任何其他组件内部的连接组件,因此最终结果如下:
谢谢。
< P>我会考虑一些选择。我的假设是相机不会移动。我没有使用过这些图像或编写过任何代码,所以这主要是根据经验- 与其只是寻找边缘,不如尝试使用分割算法分离背景。高斯混合可以帮助解决这个问题。给定同一区域(即视频)上的一组图像,可以取消持久区域。然后,新的项目,如仪器将弹出。然后可以在blob上使用连接的组件
- 我会看看分割算法,看看你是否可以优化条件,使这项工作为你。一个主要的项目是确保你的相机是稳定的,或者你自己稳定图像预处理
我会考虑使用兴趣点来识别图像中有很多新材料的区域。由于背景相对平淡,针头等小对象将创建一组兴趣点。毛巾应该稀疏得多。也许将检测到的兴趣点覆盖在连接的组件封装外形上会给您一个“密度”指标,然后您可以将其设置为阈值。如果所连接的组件对于项目区域具有较大比例的兴趣点,则它是一个有趣的对象
- 注意,您甚至可以通过使用凸面外壳修剪检测到的对象来清理连接的组件示意图。这可能有助于出现医疗器械在毛巾上投射阴影,从而拉伸部件区域的情况。这是一个猜测,但兴趣点肯定能为您提供比边缘更多的信息李>
- 最后,考虑到你有一个稳定的背景和清晰的物体,我会看一看这些特征,看看你是否能检测到图像中的每个单独的物体。这可能很有用,因为这些图像中的对象似乎具有一致的模式。你可以建立一个大的图像数据库,如针、纱布、剪刀等。然后,OpenCV中的BoF将为你找到这些候选图像。您还可以将其与正在执行的其他操作混合,以比较结果
- 使用OpenCV的功能包
-
- 使用OpenCV的功能包
- 然后设置这个反投影的阈值。这给了我们背景
- 反转背景以获得前景
- 然后找到前景的轮廓
- 以下是我尝试过的
在图像中,背景大部分是绿色的,背景的面积远远大于前景的面积。因此,如果您获取图像的颜色直方图,带绿色的箱子将具有更高的值。设置此直方图的阈值,以便将具有较小值的箱子设置为零。这样,我们很可能会保留绿色(价值更高)的箱子,并丢弃其他颜色。然后反向投影这个直方图。反向投影将突出显示图像中的这些绿色区域
反向投影:
// load the color image
IplImage* im = cvLoadImage("bFly6.jpg");
// get the color histogram
IplImage* im32f = cvCreateImage(cvGetSize(im), IPL_DEPTH_32F, 3);
cvConvertScale(im, im32f);
int channels[] = {0, 1, 2};
int histSize[] = {32, 32, 32};
float rgbRange[] = {0, 256};
float* ranges[] = {rgbRange, rgbRange, rgbRange};
CvHistogram* hist = cvCreateHist(3, histSize, CV_HIST_ARRAY, ranges);
IplImage* b = cvCreateImage(cvGetSize(im32f), IPL_DEPTH_32F, 1);
IplImage* g = cvCreateImage(cvGetSize(im32f), IPL_DEPTH_32F, 1);
IplImage* r = cvCreateImage(cvGetSize(im32f), IPL_DEPTH_32F, 1);
IplImage* backproject32f = cvCreateImage(cvGetSize(im), IPL_DEPTH_32F, 1);
IplImage* backproject8u = cvCreateImage(cvGetSize(im), IPL_DEPTH_8U, 1);
IplImage* bw = cvCreateImage(cvGetSize(im), IPL_DEPTH_8U, 1);
IplConvKernel* kernel = cvCreateStructuringElementEx(3, 3, 1, 1, MORPH_ELLIPSE);
cvSplit(im32f, b, g, r, NULL);
IplImage* planes[] = {b, g, r};
cvCalcHist(planes, hist);
// find min and max values of histogram bins
float minval, maxval;
cvGetMinMaxHistValue(hist, &minval, &maxval);
// threshold the histogram. this sets the bin values that are below the threshold to zero
cvThreshHist(hist, maxval/32);
// backproject the thresholded histogram. backprojection should contain higher values for the
// background and lower values for the foreground
cvCalcBackProject(planes, backproject32f, hist);
// convert to 8u type
double min, max;
cvMinMaxLoc(backproject32f, &min, &max);
cvConvertScale(backproject32f, backproject8u, 255.0 / max);
// threshold backprojected image. this gives us the background
cvThreshold(backproject8u, bw, 10, 255, CV_THRESH_BINARY);
// some morphology on background
cvDilate(bw, bw, kernel, 1);
cvMorphologyEx(bw, bw, NULL, kernel, MORPH_CLOSE, 2);
// get the foreground
cvSubRS(bw, cvScalar(255, 255, 255), bw);
cvMorphologyEx(bw, bw, NULL, kernel, MORPH_OPEN, 2);
cvErode(bw, bw, kernel, 1);
// find contours of the foreground
//CvMemStorage* storage = cvCreateMemStorage(0);
//CvSeq* contours = 0;
//cvFindContours(bw, storage, &contours);
//cvDrawContours(im, contours, CV_RGB(255, 0, 0), CV_RGB(0, 0, 255), 1, 2);
// grabcut
Mat color(im);
Mat fg(bw);
Mat mask(bw->height, bw->width, CV_8U);
mask.setTo(GC_PR_BGD);
mask.setTo(GC_PR_FGD, fg);
Mat bgdModel, fgdModel;
grabCut(color, mask, Rect(), bgdModel, fgdModel, GC_INIT_WITH_MASK);
Mat gcfg = mask == GC_PR_FGD;
vector<vector<cv::Point>> contours;
vector<Vec4i> hierarchy;
findContours(gcfg, contours, hierarchy, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, cv::Point(0, 0));
for(int idx = 0; idx < contours.size(); idx++)
{
drawContours(color, contours, idx, Scalar(0, 0, 255), 2);
}
// cleanup ...
我还想为你的初始版本提出一个想法。也可以跳过轮廓,其区域的宽度和高度大于图像宽度和高度的一半
//take the rect of the contours
Rect rect = Imgproc.boundingRect(contours.get(i));
if (rect.width < inputImageWidth / 2 && rect.height < inputImageHeight / 2)
//then continue to draw or use for next purposes.
//取等高线的矩形
Rect Rect=Imgproc.boundingRect(contours.get(i));
if(rect.width
谢谢您的回复。事实上,我正在手术中拍摄仪器表。开始时,所有仪器都放在桌子上,它们是w
//take the rect of the contours
Rect rect = Imgproc.boundingRect(contours.get(i));
if (rect.width < inputImageWidth / 2 && rect.height < inputImageHeight / 2)
//then continue to draw or use for next purposes.