У меня есть проблема, чтобы получить главу о контурах сглаживания и выборки в OpenCV (С++ API).
Допустим, у меня есть последовательность точек, полученных из cv::findContours
(например, применительно к этому изображению:
В конечном счете, я хочу
- Сглаживание последовательности точек с использованием разных ядер.
- Чтобы изменить размер последовательности, используя различные типы интерполяций.
После сглаживания я надеюсь получить результат, например:
Я также рассмотрел рисунок моего контура в cv::Mat
, фильтрацию Мата (используя размытие или морфологические операции) и повторное обнаружение контуров, но медленно и субоптимально. Поэтому, в идеале, я мог бы выполнять эту работу, используя исключительно точечную последовательность.
Я прочитал несколько сообщений об этом и наивно думал, что могу просто преобразовать std::vector
(of cv::Point
) в cv::Mat
, а затем функции OpenCV, такие как blur/resize, будут выполнять эту работу для меня... но они этого не сделали.
Вот что я пробовал:
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;
}
Может ли кто-нибудь объяснить, как это сделать?
Кроме того, поскольку я, вероятно, работаю с гораздо меньшими контурами, мне было интересно, как этот подход будет иметь дело с эффектом границы (например, при сглаживании, поскольку контуры являются круговыми, последние элементы последовательности должны использоваться для вычисления новое значение первых элементов...)
Большое спасибо за ваши советы,
Edit:
Я также пробовал cv::approxPolyDP()
, но, как вы можете видеть, он имеет тенденцию сохранять экстремальные точки (которые я хочу удалить):
Эпсилон = 0
Эпсилон = 6
Эпсилон = 12
Эпсилон = 24
Изменить 2:
Как предположил Бен, кажется, что cv::GaussianBlur()
не поддерживается, но cv::blur()
есть. Это выглядит намного ближе к моим ожиданиям. Вот мои результаты:
к = 13
к = 53
к = 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]);
Я все еще ищу решения для интерполяции/выборки моего контура.