2015-03-19 18 views
10

Tôi khá mới đối với OpenCV và rất vui mừng khi tìm hiểu thêm. Tôi đã chơi đùa với ý tưởng phác thảo các cạnh, hình dạng.OpenCV Edge/Phát hiện biên giới dựa trên màu

Tôi đã vượt qua mã này (chạy trên thiết bị iOS), sử dụng Canny. Tôi muốn có thể hiển thị màu này và khoanh tròn từng hình dạng. Ai đó có thể chỉ cho tôi đi đúng hướng?

Cảm ơn!

IplImage *grayImage = cvCreateImage(cvGetSize(iplImage), IPL_DEPTH_8U, 1); 
cvCvtColor(iplImage, grayImage, CV_BGRA2GRAY); 
cvReleaseImage(&iplImage); 

IplImage* img_blur = cvCreateImage(cvGetSize(grayImage), grayImage->depth, 1); 
cvSmooth(grayImage, img_blur, CV_BLUR, 3, 0, 0, 0); 
cvReleaseImage(&grayImage); 

IplImage* img_canny = cvCreateImage(cvGetSize(img_blur), img_blur->depth, 1); 
cvCanny(img_blur, img_canny, 10, 100, 3); 
cvReleaseImage(&img_blur); 

cvNot(img_canny, img_canny); 

Và ví dụ có thể là những chiếc bánh burger này. OpenCV sẽ phát hiện patty và phác thảo nó. enter image description here

gốc Hình ảnh:

enter image description here

+2

Sử dụng 'findContours' để xác định các phác thảo của tất cả các hình dạng: http://docs.opencv.org/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html#findcontours - Tiếp theo, sử dụng' drawContours' để vẽ từng hình dạng vạch ra bất kỳ màu nào bạn mong muốn: http://docs.opencv.org/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html#drawcontours. Tôi thực sự không thể nói nhiều hơn nữa cho đến khi tôi thấy những hình ảnh bạn đang cố xử lý trông như thế nào. – rayryeng

+0

@rayryeng đã thêm hình ảnh để tham khảo. Cảm ơn sự giúp đỡ của bạn – Jeff

+2

Không sao cả! Liệu nó có thể hiển thị hình ảnh thô mà không có đường viền màu đỏ? Một khi tôi nhận được điều đó, tôi có một số ý tưởng tôi muốn thử và khi tôi có một cái gì đó, tôi sẽ gửi một cái gì đó để giúp bạn ra ngoài! – rayryeng

Trả lời

43

Thông số màu sắc thường được xử lý bởi chuyển đổi sang không gian màu HSV mà xử lý "màu" trực tiếp thay vì phân chia màu sắc vào/thành phần R G/B mà làm cho nó dễ dàng hơn để xử lý cùng một màu sắc với độ sáng khác nhau vv

nếu bạn chuyển đổi hình ảnh của bạn để HSV bạn sẽ có được điều này:

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]; 
kênh

Huế:

enter image description here

Saturation kênh: kênh

enter image description here

Value:

enter image description here

thường, các kênh màu sắc là một trong những người đầu tiên nhìn vào nếu bạn là int bị xóa trong phân đoạn "màu" (ví dụ: tất cả các vật màu đỏ). Một vấn đề là, màu sắc đó là một giá trị hình tròn/góc có nghĩa là các giá trị cao nhất rất giống với các giá trị thấp nhất, kết quả là các hiện vật sáng ở biên giới của các miếng thịt. Để khắc phục điều này cho một giá trị cụ thể, bạn có thể thay đổi toàn bộ không gian màu. Nếu chuyển 50 ° bạn sẽ nhận được một cái gì đó giống như thay vì điều này:

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; 
    } 

enter image description here

bây giờ bạn có thể sử dụng một cách đơn giản phát hiện cạnh khôn ngoan để tìm các cạnh trong kênh màu sắc:

cv::Mat cannyH; 
cv::Canny(shiftedH, cannyH, 100, 50); 

enter image description here

Bạn có thể thấy rằng các khu vực lớn hơn một chút so với các chú chó con thực sự, có thể là do các phản xạ nhỏ trên rãnh und xung quanh patties, nhưng tôi không chắc chắn về điều đó.Có lẽ nó chỉ vì các hiện vật nén jpeg;)

Nếu bạn thay vì sử dụng các kênh bão hòa để giải nén cạnh, bạn sẽ kết thúc với một cái gì đó như thế này:

cv::Mat cannyS; 
cv::Canny(S, cannyS, 200, 100); 

enter image description here

nơi những đường nét không hoàn toàn đóng cửa. Có lẽ bạn có thể kết hợp màu sắc và độ bão hòa trong quá trình tiền xử lý để trích xuất các cạnh trong kênh màu nhưng chỉ ở mức độ bão hòa đủ cao.

Ở giai đoạn này, bạn có các cạnh. Cho rằng các cạnh không phải là đường nét. Nếu bạn trực tiếp trích xuất đường nét từ cạnh họ có thể không được đóng lại/etc tách:

// 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); 
} 

enter image description here

bạn có thể loại bỏ những đường nét nhỏ bằng cách kiểm tra cv::contourArea(contoursH[i]) > someThreshold trước khi vẽ. Nhưng bạn thấy hai miếng thịt ở bên trái được kết nối? Ở đây có phần khó nhất ... sử dụng một số chẩn đoán để "cải thiện" kết quả của bạn.

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. 

enter image description here

nếu bạn trích xuất đường nét từ đó nó sẽ giống như thế này:

enter image description here

Nếu bạn thay vì chỉ chọn những đường nét "bên trong" đó là chính xác những gì bạn thích:

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); 
} 

enter image description here

lưu ý rằng các đường viền và đường viền bên trong hơi mờ, vì vậy nó có thể không hoạt động cho các hình ảnh khác nhau và nếu các cạnh ban đầu được đặt tốt hơn xung quanh viền đối tượng, có thể không cần thiết. bên trong đường viền điều và 2. nếu nó vẫn còn cần thiết, sự giãn nở sẽ làm cho đối tượng nhỏ hơn trong kịch bản này (mà may mắn là rất tốt cho hình ảnh mẫu nhất định.).

EDIT: Một số thông tin quan trọng về HSV: Kênh màu sẽ cho mỗi pixel một màu của quang phổ, ngay cả khi độ bão hòa rất thấp (= xám/trắng) hoặc nếu màu rất thấp (giá trị) thường xuyên nó là mong muốn để ngưỡng các kênh bão hòa và giá trị để tìm một số màu sắc cụ thể! Điều này có thể dễ dàng hơn và khó khăn hơn nhiều để xử lý hơn là sự giãn nở mà tôi đã sử dụng trong mã của mình.

+3

Câu trả lời này thật đáng kinh ngạc.- Tôi chỉ đang đánh bạc vào thời điểm này, nhưng làm cách nào để phủ lên các đường viền trên một hình ảnh màu? – Jeff

+1

@ 1__ Tôi sẽ cập nhật sau 15 phút – Micka

+1

Chính xác những gì tôi định làm. Không có thời gian tối qua. Công việc tốt! Btw Tôi lol tại bình luận C api của bạn. Btw một câu trả lời hay. Nhắc tôi về phong cách của tôi! – rayryeng