informacja Kolor jest często traktowane przez konwersję do HSV przestrzeni barw, które obsługuje „kolor” bezpośrednio zamiast dzielić kolor w/G składowych R/B, który sprawia, że łatwiej obsługiwać te same kolory z różną jasnością itd
jeśli konwertować obraz do HSV dostaniesz to:
cv::Mat hsv;
cv::cvtColor(input,hsv,CV_BGR2HSV);
std::vector<cv::Mat> channels;
cv::split(hsv, channels);
cv::Mat H = channels[0];
cv::Mat S = channels[1];
cv::Mat V = channels[2];
Hue channel:
Nasycenie kanał: kanał
Wartość:
zwykle, kanał barwa jest pierwsza patrzeć jeśli masz int erested w segmentowaniu "koloru" (np. wszystkie czerwone obiekty). Jednym z problemów jest to, że odcień jest kolistą/kątową wartością, co oznacza, że najwyższe wartości są bardzo podobne do najniższych wartości, co skutkuje jasnymi artefaktami na granicy pasztecików. Aby przezwyciężyć to dla określonej wartości, możesz przesunąć całą przestrzeń barw. Jeśli przesunięte o 50 ° dostaniesz coś takiego zamiast:
cv::Mat shiftedH = H.clone();
int shift = 25; // in openCV hue values go from 0 to 180 (so have to be doubled to get to 0 .. 360) because of byte range from 0 to 255
for(int j=0; j<shiftedH.rows; ++j)
for(int i=0; i<shiftedH.cols; ++i)
{
shiftedH.at<unsigned char>(j,i) = (shiftedH.at<unsigned char>(j,i) + shift)%180;
}
teraz można użyć prostego wykrywania obrotny krawędzi do krawędzi znaleźć w kanale Hue
cv::Mat cannyH;
cv::Canny(shiftedH, cannyH, 100, 50);
Widać, że regiony są nieco większe od prawdziwych pasztecików, które mogą być spowodowane drobnymi odbiciami i wokół patties, ale nie jestem tego pewien.Może to tylko ze względu na artefakty kompresji JPEG;)
Jeśli zamiast korzystać z kanału nasycenia wyodrębnić krawędzie, będziesz skończyć z czymś takim:
cv::Mat cannyS;
cv::Canny(S, cannyS, 200, 100);
gdzie konturów nie są całkowicie zamknięte. Być może możesz połączyć kolor i nasycenie w ramach przetwarzania wstępnego, aby wyodrębnić krawędzie w kanale odcienia, ale tylko tam, gdzie nasycenie jest wystarczająco wysokie.
Na tym etapie masz krawędzie. Chyba, że krawędzie nie są jeszcze konturami. Jeśli bezpośrednio wyodrębnić kontury krawędzi nie może być zamknięty/oddzielony itp:
// extract contours of the canny image:
std::vector<std::vector<cv::Point> > contoursH;
std::vector<cv::Vec4i> hierarchyH;
cv::findContours(cannyH,contoursH, hierarchyH, CV_RETR_TREE , CV_CHAIN_APPROX_SIMPLE);
// draw the contours to a copy of the input image:
cv::Mat outputH = input.clone();
for(int i = 0; i< contoursH.size(); i++)
{
cv::drawContours(outputH, contoursH, i, cv::Scalar(0,0,255), 2, 8, hierarchyH, 0);
}
można usunąć te małe kontury sprawdzając cv::contourArea(contoursH[i]) > someThreshold
przed wyciągnięciem. Ale widzisz dwa patties po lewej, które mają być połączone? Tutaj jest najtrudniejsza część ... użyj heurystyki, aby "poprawić" twój wynik.
cv::dilate(cannyH, cannyH, cv::Mat());
cv::dilate(cannyH, cannyH, cv::Mat());
cv::dilate(cannyH, cannyH, cv::Mat());
Dilation before contour extraction will "close" the gaps between different objects but increase the object size too.
jeśli wyodrębnić kontury, że będzie to wyglądać tak:
Jeśli zamiast wybrać tylko „wewnętrzny” kontury to jest dokładnie to, co chcesz:
cv::Mat outputH = input.clone();
for(int i = 0; i< contoursH.size(); i++)
{
if(cv::contourArea(contoursH[i]) < 20) continue; // ignore contours that are too small to be a patty
if(hierarchyH[i][3] < 0) continue; // ignore "outer" contours
cv::drawContours(outputH, contoursH, i, cv::Scalar(0,0,255), 2, 8, hierarchyH, 0);
}
należy pamiętać, że dylatacja i wewnętrzne elementy konturu są trochę rozmyte, więc może nie działać dla różnych obrazów, a jeśli początkowe krawędzie są lepiej ułożone wokół obramowania obiektu, może 1. nie trzeba wykonywać rozszerzania i wewnętrzna rzecz konturu i 2. jeśli jest to nadal konieczne, rozszerzenie spowoduje zmniejszenie obiektu w tym scenariuszu (który na szczęście jest wielki dla danego obrazu próbki.).
EDYCJA: Kilka ważnych informacji o HSV: kanał odcienia nadaje każdemu pikselowi kolor widma, nawet jeśli nasycenie jest bardzo niskie (= szaro/białe) lub jeśli kolor jest bardzo niski (wartość) tak często pożądane jest progowanie kanałów nasycenia i wartości w celu znalezienia określonego koloru! To może być o wiele łatwiejsze i dużo łatwiejsze w obsłudze niż dylatacja, której użyłem w moim kodzie.
Użyj 'findContours' aby określić kontury wszystkich kształtów: http://docs.opencv.org/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html#findcontours - Następnie użyj' drawContours', aby narysować każdy z elementów kontury w dowolnym kolorze, który chcesz: http://docs.opencv.org/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html#drawcontours. Nie mogę powiedzieć nic więcej, dopóki nie zobaczę, jak wyglądają obrazy, które próbujesz przetwarzać. – rayryeng
@rayryeng dodał (a) obraz do odsyłacza. Dzięki za pomoc – Jeff
Bez problemu! Czy możliwe byłoby ukazanie surowego obrazu bez czerwonego konturu? Kiedy już to dostanę, mam kilka pomysłów, które chciałbym wypróbować, a kiedy coś mam, opublikuję coś, co ci pomoże! – rayryeng