OpenCV (C++ API) で輪郭のスムージングとサンプリングに頭を悩ませています。ポイントのシーケンスを取得したとしましょうcv::findContours
(たとえば、この画像に適用されます:
最終的に、私はしたいです
- 異なるカーネルを使用して一連のポイントを滑らかにします。
- さまざまな種類の補間を使用してシーケンスのサイズを変更します。
平滑化後、次のような結果が得られることを願っています。
また、 で輪郭を描画しcv::Mat
、マットをフィルタリングし (ぼかしまたはモルフォロジー操作を使用)、輪郭を再検出することも検討しましたが、遅くて最適ではありません。したがって、理想的には、点列だけを使用して仕事をすることができました。
私はそれに関するいくつかの投稿を読み、a std::vector
(of cv::Point
) を aに変換するだけでcv::Mat
、blur/resize などの 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()
ましたが、ご覧のとおり、極値を保持する傾向があります(削除したい):
イプシロン=0
イプシロン=6
イプシロン=12
イプシロン=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]);
輪郭を補間/サンプリングするソリューションをまだ探しています。