【发布时间】:2012-08-09 04:17:51
【问题描述】:
在 OpenCV (C++ API) 中,我很难理解平滑和采样轮廓。
假设我已经从cv::findContours 检索到点序列(例如应用于此图像:
最终,我想要
- 使用不同的内核平滑一系列点。
- 使用不同类型的插值调整序列大小。
平滑后,我希望有这样的结果:
我还考虑在cv::Mat 中绘制我的轮廓,过滤 Mat(使用模糊或形态学操作)并重新找到轮廓,但速度很慢且次优。所以,理想情况下,我可以只使用点序列来完成这项工作。
我阅读了一些关于它的帖子,并天真地认为我可以简单地将std::vector(cv::Point)转换为cv::Mat,然后像模糊/调整大小这样的OpenCV函数就可以为我完成这项工作......但他们没有。
这是我尝试过的:
int main( int argc, char** argv ){
cv::Mat conv,ori;
ori=cv::imread(argv[1]);
ori.copyTo(conv);
cv::cvtColor(ori,ori,CV_BGR2GRAY);
std::vector<std::vector<cv::Point> > contours;
std::vector<cv::Vec4i > hierarchy;
cv::findContours(ori, contours,hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_NONE);
for(int k=0;k<100;k += 2){
cv::Mat smoothCont;
smoothCont = cv::Mat(contours[0]);
std::cout<<smoothCont.rows<<"\t"<<smoothCont.cols<<std::endl;
/* Try smoothing: no modification of the array*/
// cv::GaussianBlur(smoothCont, smoothCont, cv::Size(k+1,1),k);
/* Try sampling: "Assertion failed (func != 0) in resize"*/
// cv::resize(smoothCont,smoothCont,cv::Size(0,0),1,1);
std::vector<std::vector<cv::Point> > v(1);
smoothCont.copyTo(v[0]);
cv::drawContours(conv,v,0,cv::Scalar(255,0,0),2,CV_AA);
std::cout<<k<<std::endl;
cv::imshow("conv", conv);
cv::waitKey();
}
return 1;
}
谁能解释一下如何做到这一点?
此外,由于我可能使用更小的轮廓,我想知道这种方法将如何处理边界效果(例如,在平滑时,由于轮廓是圆形的,因此必须使用序列的最后一个元素来计算第一个元素的新值...)
非常感谢您的建议,
编辑:
我也尝试过cv::approxPolyDP(),但正如您所见,它倾向于保留极值点(我想删除):
Epsilon=0
Epsilon=6
Epsilon=12
Epsilon=24
编辑 2:
正如 Ben 所建议的,似乎不支持 cv::GaussianBlur(),但支持 cv::blur()。它看起来非常接近我的预期。这是我使用它的结果:
k=13
k=53
k=103
为了绕过边框效果,我做了:
cv::copyMakeBorder(smoothCont,smoothCont, (k-1)/2,(k-1)/2 ,0, 0, cv::BORDER_WRAP);
cv::blur(smoothCont, result, cv::Size(1,k),cv::Point(-1,-1));
result.rowRange(cv::Range((k-1)/2,1+result.rows-(k-1)/2)).copyTo(v[0]);
我仍在寻找对我的轮廓进行插值/采样的解决方案。
【问题讨论】:
-
任何想法将轮廓调整为固定长度?
标签: c++ opencv contour sampling