In this Post I demonstrating how object can be segmented using OpenCV inRange function, where we use HSV colour space instead of BGR. HSV (hue, saturation, value) color-space is a model to represent the colorspace similar to the RGB. And hue channel is the only color type, it is easier to segment color in HSV color space.
The source code below will do the colour segmentation based on the HSV Minimum and Max Value selected using slider, the Min and Max value can be selected by clicking the color rectangle on HSV MIN and HSV MAX sub-window. See the demo video for how the value can be selected. The output show HSV representation of image, the threshold after inrange operation and segmented RGB image.
The source code below will do the colour segmentation based on the HSV Minimum and Max Value selected using slider, the Min and Max value can be selected by clicking the color rectangle on HSV MIN and HSV MAX sub-window. See the demo video for how the value can be selected. The output show HSV representation of image, the threshold after inrange operation and segmented RGB image.
Demo Video
C++ Code
Here is the steps in the source code in brief.- Load image
- Convert To HSV
- inRange create mask image for segment ion.
- Segment the image using above mask
int R,G,B,H,S,V;
int hue_val =50;
int sat_val =100;
int val_val =100;
int winWidth = 1920;
int winHeight = 1080;
int H_MIN = 50;
int S_MIN = 100;
int V_MIN = 100;
int H_MAX = 179;
int S_MAX = 255;
int V_MAX = 255;
int skip_counter = 3;
Rect HSV_MIN_RECT = Rect(winWidth*.04,winHeight*.6,winWidth*.08,winWidth*.08);
Rect HSV_MAX_RECT = Rect(winWidth*.19,winHeight*.6,winWidth*.08,winWidth*.08);
Rect SUB_WIN1_RECT = Rect(0, 0, winWidth/2,winHeight/2);
Rect SUB_WIN2_RECT = Rect(winWidth/2, 0, winWidth/2,winHeight/2);
bool hsv_min_selected = true;
char window_name[30] = "HSV Color Segmentation";
Mat window;
Mat src_Img;
Scalar Scalar_HSV_TO_BGR(uchar H, uchar S, uchar V) {
Mat rgb;
Mat hsv(1,1, CV_8UC3, Scalar(H,S,V));
cvtColor(hsv, rgb, COLOR_HSV2BGR);
return Scalar(rgb.data[0], rgb.data[1], rgb.data[2]);
//return Scalar(hsv.data[0], hsv.data[1], hsv.data[2]);
}
void highlight_HSV_Draw(){
skip_counter = 0;
Mat subWin1 = window(Rect(0,window.rows*.5,window.cols*.33,window.rows/2));
subWin1.setTo(Scalar::all(0));
Scalar hsv_max_color(255,255,255);
Scalar hsv_min_color(255,255,255);
if(hsv_min_selected){
hsv_min_color = Scalar(0,255,0);
setTrackbarPos("HUE", window_name,H_MIN);
setTrackbarPos("SAT", window_name,S_MIN);
setTrackbarPos("VAL", window_name,V_MIN);
}
else{
hsv_max_color = Scalar(0,255,0);
setTrackbarPos("HUE", window_name,H_MAX);
setTrackbarPos("SAT", window_name,S_MAX);
setTrackbarPos("VAL", window_name,V_MAX);
}
cv::putText(window, format("H MIN = %d",H_MIN), cv::Point(winWidth*.05-50,winHeight*.8+40), FONT_HERSHEY_PLAIN, 2, hsv_min_color, 2,LINE_AA);
cv::putText(window, format("S MIN = %d",S_MIN), cv::Point(winWidth*.05-50,winHeight*.8+80),FONT_HERSHEY_PLAIN, 2, hsv_min_color, 2,LINE_AA);
cv::putText(window, format("V MIN = %d",V_MIN), cv::Point(winWidth*.05-50,winHeight*.8+120), FONT_HERSHEY_PLAIN, 2, hsv_min_color, 2,LINE_AA);
cv::putText(window, format("H MAX = %d",H_MAX), cv::Point(winWidth*.2-50,winHeight*.8+40), FONT_HERSHEY_PLAIN, 2, hsv_max_color, 2,LINE_AA);
cv::putText(window, format("S MAX = %d",S_MAX), cv::Point(winWidth*.2-50,winHeight*.8+80), FONT_HERSHEY_PLAIN, 2, hsv_max_color, 2,LINE_AA);
cv::putText(window, format("V MAX = %d",V_MAX), cv::Point(winWidth*.2-50,winHeight*.8+120), FONT_HERSHEY_PLAIN, 2, hsv_max_color, 2,LINE_AA);
//draw HSV value section
rectangle(window,HSV_MIN_RECT,Scalar_HSV_TO_BGR(H_MIN,S_MIN,V_MIN),FILLED,LINE_AA);
rectangle(window,HSV_MAX_RECT,Scalar_HSV_TO_BGR(H_MAX,S_MAX,V_MAX),FILLED,LINE_AA);
//draw window border
line(window,Point(0,window.rows*.5),Point(window.cols*.33,window.rows*.5),Scalar(255,255,255),2,LINE_AA);
line(window,Point(window.cols*.33,window.rows*.5),Point(window.cols*.33,window.rows),Scalar(255,255,255),2,LINE_AA);
//draw window title
cv::putText(window, "HSV MIN", cv::Point(winWidth*.04,winHeight*.5+60), FONT_HERSHEY_TRIPLEX, 1.0, hsv_min_color, 2,LINE_AA);
cv::putText(window, "HSV MAX", cv::Point(winWidth*.19,winHeight*.5+60), FONT_HERSHEY_TRIPLEX, 1.0, hsv_max_color, 2,LINE_AA);
imshow(window_name,window);
}
Mat HSV_Color_Segment(){
Mat HSV;
Mat thr;
// Convert from BGR to HSV colorspace
cvtColor(src_Img, HSV, COLOR_BGR2HSV);
// Detect the object based on HSV Range Values
inRange(HSV, Scalar(H_MIN, S_MIN, V_MIN), Scalar(H_MAX, S_MAX, V_MAX), thr);
return thr;
}
void updateUI(){
if(skip_counter<3){
skip_counter++;
return;
}
Mat subWin1 = window(Rect(0,window.rows*.5,window.cols*.33,window.rows/2));
subWin1.setTo(Scalar::all(0));
Scalar hsv_max_color(255,255,255);
Scalar hsv_min_color(255,255,255);
if(hsv_min_selected){
H_MIN = hue_val;
S_MIN = sat_val;
V_MIN = val_val;
hsv_min_color = Scalar(0,255,0);
}
else{
H_MAX = hue_val;
S_MAX = sat_val;
V_MAX = val_val;
hsv_max_color = Scalar(0,255,0);
}
cv::putText(window, format("H MIN = %d",H_MIN), cv::Point(winWidth*.05-50,winHeight*.8+40), FONT_HERSHEY_PLAIN, 2, hsv_min_color, 2,LINE_AA);
cv::putText(window, format("S MIN = %d",S_MIN), cv::Point(winWidth*.05-50,winHeight*.8+80),FONT_HERSHEY_PLAIN, 2, hsv_min_color, 2,LINE_AA);
cv::putText(window, format("V MIN = %d",V_MIN), cv::Point(winWidth*.05-50,winHeight*.8+120), FONT_HERSHEY_PLAIN, 2, hsv_min_color, 2,LINE_AA);
cv::putText(window, format("H MAX = %d",H_MAX), cv::Point(winWidth*.2-50,winHeight*.8+40), FONT_HERSHEY_PLAIN, 2, hsv_max_color, 2,LINE_AA);
cv::putText(window, format("S MAX = %d",S_MAX), cv::Point(winWidth*.2-50,winHeight*.8+80), FONT_HERSHEY_PLAIN, 2, hsv_max_color, 2,LINE_AA);
cv::putText(window, format("V MAX = %d",V_MAX), cv::Point(winWidth*.2-50,winHeight*.8+120), FONT_HERSHEY_PLAIN, 2, hsv_max_color, 2,LINE_AA);
//draw HSV value section
rectangle(window,HSV_MIN_RECT,Scalar_HSV_TO_BGR(H_MIN,S_MIN,V_MIN),FILLED,LINE_AA);
rectangle(window,HSV_MAX_RECT,Scalar_HSV_TO_BGR(H_MAX,S_MAX,V_MAX),FILLED,LINE_AA);
//draw window border
line(window,Point(0,window.rows*.5),Point(window.cols*.33,window.rows*.5),Scalar(255,255,255),2,LINE_AA);
line(window,Point(window.cols*.33,window.rows*.5),Point(window.cols*.33,window.rows),Scalar(255,255,255),2,LINE_AA);
//draw window title
cv::putText(window, "HSV MIN", cv::Point(winWidth*.04,winHeight*.5+60), FONT_HERSHEY_TRIPLEX, 1.0, hsv_min_color, 2,LINE_AA);
cv::putText(window, "HSV MAX", cv::Point(winWidth*.19,winHeight*.5+60), FONT_HERSHEY_TRIPLEX, 1.0, hsv_max_color, 2,LINE_AA);
//Do Color segmanetiaon and Draw Image on window
Mat thr = HSV_Color_Segment();
Mat thrBGR;
cvtColor(thr,thrBGR,COLOR_GRAY2BGR);
resize(thrBGR,thrBGR,Size(winWidth*.33,winHeight/2));
thrBGR.copyTo(window(Rect(winWidth*.33,winHeight*.5, winWidth*.33,winHeight/2)));
Mat segmented;
src_Img.copyTo(segmented,thr);
resize(segmented,segmented,Size(winWidth*.33,winHeight/2));
segmented.copyTo(window(Rect(winWidth*.66,winHeight*.5, winWidth*.33,winHeight/2)));
//Draw output window title
rectangle(window,Rect(winWidth*.43-30,winHeight*.5+3,250,60),Scalar(0,0,0),FILLED,LINE_AA);
rectangle(window,Rect(winWidth*.76-30,winHeight*.5+3,250,60),Scalar(0,0,0),FILLED,LINE_AA);
cv::putText(window, "Threshold", cv::Point(winWidth*.43,winHeight*.5+40), FONT_HERSHEY_TRIPLEX, 1.0, Scalar(255,255,255), 2,LINE_AA);
cv::putText(window, "Segmented", cv::Point(winWidth*.76,winHeight*.5+40), FONT_HERSHEY_TRIPLEX, 1.0, Scalar(255,255,255), 2,LINE_AA);
//draw RGB HSV value on mouse pointer
cv::putText(window, format("B=%d G=%d R=%d H=%d S=%d V=%d",B,G,R,H,S,V), cv::Point(10,winHeight-20), FONT_HERSHEY_SIMPLEX, .7, Scalar(0,0,255), 2,LINE_AA);
imshow(window_name,window);
}
static void onMouse( int event, int x, int y, int f, void* ){
if(f&EVENT_FLAG_LBUTTON){
//check HSV Rect clicked or not
if(HSV_MIN_RECT.contains(Point(x,y)))
hsv_min_selected = true;
else if(HSV_MAX_RECT.contains(Point(x,y)))
hsv_min_selected = false;
highlight_HSV_Draw();
}
else if(f==EVENT_MOUSEMOVE){
// Took color on first three window only
//if(HSV_MIN_RECT.contains(Point(x,y))||HSV_MAX_RECT.contains(Point(x,y))||SUB_WIN1_RECT.contains(Point(x,y))||SUB_WIN2_RECT.contains(Point(x,y))){
//draw HSV and RGB Value on Image
Mat subWin = window(Rect(0,winHeight-60,window.cols*.33,60));
subWin.setTo(Scalar::all(0));
Mat HSV;
Mat BGR=window(Rect(x,y,1,1));
cvtColor(BGR, HSV,COLOR_BGR2HSV);
B = BGR.data[0]; G = BGR.data[1]; R = BGR.data[2];
H = HSV.data[0]; S = HSV.data[1]; V = HSV.data[2];
cv::putText(window, format("B=%d G=%d R=%d H=%d S=%d V=%d",B,G,R,H,S,V), cv::Point(10,winHeight-20), FONT_HERSHEY_SIMPLEX, .7, Scalar(0,0,255), 2,LINE_AA);
imshow(window_name,window);
//}
}
}
static void on_trackbar_changed(int, void*){
updateUI();
}
int main()
{
window = Mat(winHeight,winWidth,CV_8UC3,Scalar::all(0));
src_Img = imread("img/shapes.jpg", IMREAD_COLOR);
Mat resizeSrc;
resize(src_Img,resizeSrc,Size(winWidth/2,winHeight/2)); //resize to fit on input widnow
Mat HSV;
cvtColor(resizeSrc, HSV,COLOR_BGR2HSV);
resizeSrc.copyTo(window(SUB_WIN1_RECT)); //copy input to window
HSV.copyTo(window(SUB_WIN2_RECT)); //copy HSV to window
namedWindow(window_name, WINDOW_NORMAL); // Create Window
resizeWindow(window_name,winWidth,winHeight);
createTrackbar( "HUE", window_name, &hue_val, 179, on_trackbar_changed );
createTrackbar( "SAT", window_name, &sat_val, 255,on_trackbar_changed );
createTrackbar( "VAL", window_name, &val_val, 255, on_trackbar_changed );
setTrackbarPos("HUE", window_name,H_MIN);
setTrackbarPos("SAT", window_name,S_MIN);
setTrackbarPos("VAL", window_name,V_MIN);
setMouseCallback( window_name, onMouse, 0 );
//Title for Window
rectangle(window,Rect(winWidth*.2-30,5,250,60),Scalar(0,0,0),FILLED,LINE_AA);
rectangle(window,Rect(winWidth*.72-40,5,150,60),Scalar(0,0,0),FILLED,LINE_AA);
cv::putText(window, "Input(BGR)", cv::Point(winWidth*.2, 40), FONT_HERSHEY_TRIPLEX, 1.0, CV_RGB(255, 255,255), 2,LINE_AA);
cv::putText(window, "HSV", cv::Point(winWidth*.72, 40), FONT_HERSHEY_TRIPLEX, 1.0, CV_RGB(255, 255,255), 2,LINE_AA);
//draw window border
line(window,Point(0,window.rows*.5),Point(window.cols,window.rows*.5),Scalar(255,255,255),3,LINE_AA);
line(window,Point(window.cols*.5,0),Point(window.cols*.5,window.rows*.5),Scalar(255,255,255),3,LINE_AA);
line(window,Point(window.cols*.33,window.rows*.5),Point(window.cols*.33,window.rows),Scalar(255,255,255),3,LINE_AA);
line(window,Point(window.cols*.66,window.rows*.5),Point(window.cols*.66,window.rows),Scalar(255,255,255),3,LINE_AA);
updateUI();
while(true)
{
int c;
c = waitKey( 20 );
if( (char)c == 27 )
{ break; }
}
return 0;
}
No comments:
Post a Comment