My represent 20 colors are bring from paint app in window.
RGB value of 20 colors are composed..
{0,0,0}, //0
{127,127,127}, //1
{136,0,21},
{237,28,36},
{255127,39},
{255,242,0},
{34,177,76},
{0,162,232},
{63,72,204},
{163,73,164},
{255,255,255}, //10
{195,195,195}, //11
{185,122,87},
{255,174,201},
{255,201,14},
{239,228,176},
{181,230,29},
{153,217,234},
{112,146,190},
{200,191,231}
Input color is examined that standard deviation is lower than threshold.
The lower STD value means that close to gray family color.
Our sample code is determined to be gray when the STD value is smaller than 4.
The value of 4 is heuristic value.
When the input color is not gray scale, out sample find the similarity in the following five methods.
1.
input rgb -> hsv -> conic VS represent 20 conic values
2.
input rgb -> hsv -> cylindric VS represent 20 cylidric values
3.
input rgb -> YCbCr VS represent 20 YCbCr values
4.
input rgb -> CbCr VS represent 20 CbCr values
5.
input rgb VS represent 20 rgb
VS means uclidean distance.
The minimum distance was best mathicng color.
The input color is seletect by random.
The matching result is expressed by jpg file and imshow.
I hope you determine what is the the best way in 5 method.
And there can be a better way.
More detail refer to example source code.
...
#define SAT_TH 20 #include < opencv2\opencv.hpp> #include < string> #include < stdio.h> #include < time.h> #ifdef _DEBUG #pragma comment(lib, "opencv_core249d.lib") #pragma comment(lib, "opencv_imgproc249d.lib") //MAT processing #pragma comment(lib, "opencv_highgui249d.lib") #define _DEBUG_RRRR #else #pragma comment(lib, "opencv_core249.lib") #pragma comment(lib, "opencv_imgproc249.lib") #pragma comment(lib, "opencv_highgui249.lib") //#define _DEBUG_RRRR #endif using namespace std; using namespace cv; struct RGB_QUAD{ int r, g, b; }; RGB_QUAD base_rgb[20] = { {0,0,0}, //0 {127,127,127}, //1 {136,0,21}, {237,28,36}, {255127,39}, {255,242,0}, {34,177,76}, {0,162,232}, {63,72,204}, {163,73,164}, {255,255,255}, //10 {195,195,195}, //11 {185,122,87}, {255,174,201}, {255,201,14}, {239,228,176}, {181,230,29}, {153,217,234}, {112,146,190}, {200,191,231} }; string rgb_name[20] = {"black", "gray", "Brown", "Red", "Orange", "Yellow", "Green", "Sky Blue", "Blue", "Violet", "White", "Light Gray", "Ocher", "Pink", "Light Orange", "Light Yellow", "Light Green", "Light Sky Blue", "Light Blue", "Light Violet"}; struct hsv_color { unsigned char h; // Hue: 0 ~ 255 (red:0, gree: 85, blue: 171) unsigned char s; // Saturation: 0 ~ 255 unsigned char v; // Value: 0 ~ 255 }; hsv_color base_hsv[20] = {{0, 0, 0}, {0, 0, 127}, {250, 255, 136}, {255, 224, 237}, {17, 216, 255}, {40, 255, 255}, {97, 206, 177}, {141, 255, 232}, {169, 176, 204}, {213, 141, 164}, {0, 0, 255}, {0, 0, 195}, {15, 135, 185}, {242, 81, 255}, {33, 241, 255}, {35, 67, 239}, {53, 222, 230}, {138, 88, 234}, {153, 104, 190}, {180, 44, 231}}; struct my_xyz { float x; float y; float z; }; my_xyz base_hsv_conic[20] = { {0.00, 0.00, 0.00}, {0.00, 0.00, 127.00}, {134.97, -16.74, 136.00}, {208.19, -0.04, 237.00}, {197.33, 87.85, 255.00}, {140.86, 212.56, 255.00}, {-104.47, 97.63, 177.00}, {-219.29, -75.73, 232.00}, {-73.40, -120.16, 204.00}, {46.29, -77.98, 164.00}, {0.00, 0.00, 255.00}, {0.00, 0.00, 195.00}, {91.33, 35.38, 185.00}, {76.88, -25.52, 255.00}, {165.63, 175.07, 255.00}, {40.86, 47.69, 239.00}, {52.43, 193.25, 230.00}, {-78.07, -20.65, 234.00}, {-62.70, -45.54, 190.00}, {-10.91, -38.34, 231.00}}; my_xyz base_hsv_cylindric[20] = { {0.00, 0.00, 0.00}, {0.00, 0.00, 127.00}, {253.06, -31.38, 136.00}, {224.00, -0.04, 237.00}, {197.33, 87.85, 255.00}, {140.86, 212.56, 255.00}, {-150.50, 140.66, 177.00}, {-241.03, -83.24, 232.00}, {-91.75, -150.19, 204.00}, {71.98, -121.24, 164.00}, {0.00, 0.00, 255.00}, {0.00, 0.00, 195.00}, {125.88, 48.77, 185.00}, {76.88, -25.52, 255.00}, {165.63, 175.07, 255.00}, {43.59, 50.88, 239.00}, {58.13, 214.26, 230.00}, {-85.07, -22.51, 234.00}, {-84.14, -61.12, 190.00}, {-12.05, -42.32, 231.00} }; struct my_ycbcr { float Y; float Cb; float Cr; }; my_ycbcr base_ycbcr[20] = { {0.00, 128.00, 128.00}, {127.00, 128.00, 128.00}, {43.00, 115.59, 112.31}, {91.00, 96.96, 88.77}, {68.00, 89.63, 79.50}, {218.00, 4.98, -27.48}, {122.00, 102.04, 95.19}, {121.00, 190.64, 207.17}, {84.00, 195.72, 213.58}, {110.00, 158.47, 166.51}, {255.00, 128.00, 128.00}, {195.00, 128.00, 128.00}, {136.00, 100.35, 93.05}, {201.00, 128.00, 128.00}, {195.00, 25.86, -1.09}, {225.00, 100.35, 93.05}, {192.00, 36.02, 11.75}, {199.00, 147.75, 152.96}, {140.00, 156.21, 163.66}, {198.00, 146.62, 151.54} }; #define SAT_TH 20 #define STD_TH 5 #define MININ3(x,y,z) ( (y) <= (z) ? ((x) <= (y) ? (x) : (y)) : ((x) <= (z) ? (x) : (z)) ) #define MAXIN3(x,y,z) ( (y) >= (z) ? ((x) >= (y) ? (x) : (y)) : ((x) >= (z) ? (x) : (z)) ) int findColsetColorIndexInHSV_conic(int R, int G, int B); int findColsetColorIndexInHSV_cylindric(int R, int G, int B); int findColsetColorIndexInYCbCr(int R, int G, int B); int findColsetColorIndexInYCbCr2(int R, int G, int B); int findColsetColorIndexInRGB(int R, int G, int B); int findColsetColorIndexInGRAYScale(int R, int G, int B); float uDist(float a1, float b1, float c1, float a2, float b2, float c2); float uDist2(float a1, float b1, float a2, float b2); hsv_color RGB2HSV(unsigned char r, unsigned char g, unsigned char b); my_ycbcr rgb2ycbcr(unsigned char r, unsigned char g, unsigned char b); my_xyz HSV2conic(unsigned char h, unsigned char s, unsigned char v); my_xyz HSV2Cylindric(unsigned char h, unsigned char s, unsigned char v); void matchingColorinTable(int inR, int inG, int inB); float getSTDrgb(int R, int G, int B); void main() { srand( time(0) ); printf( "%d \n", rand( ) ); //draw represent 20 colors int colorN = 20; Mat ColorTable(50,50*colorN, CV_8UC3); for(int i=0; i< colorN; ++i) { rectangle(ColorTable, Rect(i*50, 0, i*50+50, 50), CV_RGB(base_rgb[i].r, base_rgb[i].g, base_rgb[i].b),-1 ); } imshow("ColorTable", ColorTable ); imwrite("colortable.jpg", ColorTable); for(int i=0; i< 200; ++i) { int r = rand() %255; int g = rand() %255; int b = rand() %255; printf("%d %d %d \n", r,g,b); //matching matchingColorinTable(r, g, b); waitKey(0); } } void matchingColorinTable(int inR, int inG, int inB) { //matching //step 1. get rgb standard deviation hsv_color hsv; hsv = RGB2HSV(inR, inG, inB); float std = getSTDrgb(inR, inG, inB); //printf("std = %lf \n", std ); int findClosetColorIndex=-1; if(STD_TH > std) //if(SAT_TH > hsv.s ) { //input rgb can be gray scale color. findClosetColorIndex = findColsetColorIndexInGRAYScale(inR, inG, inB); Mat inColor(50,50*2, CV_8UC3); rectangle(inColor, Rect(0, 0, 50, 50), CV_RGB(inR, inG, inB),-1 ); rectangle(inColor, Rect(50, 0, 50, 50), CV_RGB(base_rgb[findClosetColorIndex].r, base_rgb[findClosetColorIndex].g, base_rgb[findClosetColorIndex].b),-1 ); imshow("your color and matched color", inColor ); char str[100]; sprintf(str,"gray_%d_%d_%d.jpg", inR, inG, inB ); imwrite( str, inColor); }else{ //step 2. find closest color by uclidiean distant Mat inColor(50*5,50*2, CV_8UC3); //#1 hsv conic rectangle(inColor, Rect(0, 0, 50, 50), CV_RGB(inR, inG, inB),-1 ); findClosetColorIndex = findColsetColorIndexInHSV_conic(inR, inG, inB); rectangle(inColor, Rect(50, 0, 50, 50), CV_RGB(base_rgb[findClosetColorIndex].r, base_rgb[findClosetColorIndex].g, base_rgb[findClosetColorIndex].b),-1 ); rectangle(inColor, Rect(0, 0, 100, 50), CV_RGB(0,0,0),1 ); //#2 hsv cylidric rectangle(inColor, Rect(0, 50*1, 50, 50), CV_RGB(inR, inG, inB),-1 ); findClosetColorIndex = findColsetColorIndexInHSV_cylindric(inR, inG, inB); rectangle(inColor, Rect(50, 50*1, 50, 50), CV_RGB(base_rgb[findClosetColorIndex].r, base_rgb[findClosetColorIndex].g, base_rgb[findClosetColorIndex].b),-1 ); rectangle(inColor, Rect(0, 50, 100, 50), CV_RGB(0,0,0),1 ); //#3 ycbcr rectangle(inColor, Rect(0, 50*2, 50, 50), CV_RGB(inR, inG, inB),-1 ); findClosetColorIndex = findColsetColorIndexInYCbCr(inR, inG, inB); rectangle(inColor, Rect(50, 50*2, 50, 50), CV_RGB(base_rgb[findClosetColorIndex].r, base_rgb[findClosetColorIndex].g, base_rgb[findClosetColorIndex].b),-1 ); rectangle(inColor, Rect(0, 100, 100, 50), CV_RGB(0,0,0),1 ); //#4 cbcr rectangle(inColor, Rect(0, 50*3, 50, 50), CV_RGB(inR, inG, inB),-1 ); findClosetColorIndex = findColsetColorIndexInYCbCr2(inR, inG, inB); rectangle(inColor, Rect(50, 50*3, 50, 50), CV_RGB(base_rgb[findClosetColorIndex].r, base_rgb[findClosetColorIndex].g, base_rgb[findClosetColorIndex].b),-1 ); rectangle(inColor, Rect(0, 150, 100, 50), CV_RGB(0,0,0),1 ); //#5 rgb rectangle(inColor, Rect(0, 50*4, 50, 50), CV_RGB(inR, inG, inB),-1 ); findClosetColorIndex = findColsetColorIndexInRGB(inR, inG, inB); rectangle(inColor, Rect(50, 50*4, 50, 50), CV_RGB(base_rgb[findClosetColorIndex].r, base_rgb[findClosetColorIndex].g, base_rgb[findClosetColorIndex].b),-1 ); rectangle(inColor, Rect(0, 200, 100, 50), CV_RGB(0,0,0),1 ); imshow("your color and matched color", inColor ); char str[100]; sprintf(str,"%d_%d_%d.jpg", inR, inG, inB ); imwrite( str, inColor); } //draw input color and matched color printf("find color index = %d\n", findClosetColorIndex); //print input hsv, match hsv printf("input hsv=%d, %d, %d => match %d, %d, %d \n", hsv.h, hsv.s, hsv.v, base_hsv[findClosetColorIndex].h, base_hsv[findClosetColorIndex].s, base_hsv[findClosetColorIndex].v ); } float uDist(float a1, float b1, float c1, float a2, float b2, float c2) { float dist = sqrt( (a1-a2)*(a1-a2)+(b1-b2)*(b1-b2)+(c1-c2)*(c1-c2) ); return dist; } float uDist2(float a1, float b1, float a2, float b2) { float dist = sqrt( (a1-a2)*(a1-a2)+(b1-b2)*(b1-b2)); return dist; } int findColsetColorIndexInGRAYScale(int R, int G, int B) { int index=-1; float minDist=1000000; for(int i=0; i< 20; ++i) { //non gray scale pass if( !( (base_rgb[i].r == base_rgb[i].b) && (base_rgb[i].b == base_rgb[i].g ) ) ) continue; float dist = uDist(R, G, B, base_rgb[i].r, base_rgb[i].g, base_rgb[i].b); if(dist < minDist) { minDist = dist; index = i; } } return index; } int findColsetColorIndexInHSV_conic(int R, int G, int B) { int index=-1; float minDist=1000000; for(int i=0; i< 20; ++i) { //gray scale pass if( ( (base_rgb[i].r == base_rgb[i].b) && (base_rgb[i].b == base_rgb[i].g ) ) ) continue; //rgb to hsv hsv_color hsv; hsv = RGB2HSV(R, G, B); //hsv to conic my_xyz xyz; xyz = HSV2conic(hsv.h, hsv.s, hsv.v); //distance float dist = uDist(xyz.x, xyz.y, xyz.z, base_hsv_conic[i].x, base_hsv_conic[i].y, base_hsv_conic[i].z); //min dist if(dist < minDist) { minDist = dist; index = i; } } return index; } int findColsetColorIndexInHSV_cylindric(int R, int G, int B) { int index=-1; float minDist=1000000; for(int i=0; i< 20; ++i) { //gray scale pass if( ( (base_rgb[i].r == base_rgb[i].b) && (base_rgb[i].b == base_rgb[i].g ) ) ) continue; //rgb to hsv hsv_color hsv; hsv = RGB2HSV(R, G, B); //hsv to conic my_xyz xyz; xyz = HSV2Cylindric(hsv.h, hsv.s, hsv.v); //distance float dist = uDist(xyz.x, xyz.y, xyz.z, base_hsv_cylindric[i].x, base_hsv_cylindric[i].y, base_hsv_cylindric[i].z); //min dist if(dist < minDist) { minDist = dist; index = i; } } return index; } int findColsetColorIndexInYCbCr(int R, int G, int B) { int index=-1; float minDist=1000000; for(int i=0; i< 20; ++i) { //gray scale pass if( ( (base_rgb[i].r == base_rgb[i].b) && (base_rgb[i].b == base_rgb[i].g ) ) ) continue; //rgb to ycbcr my_ycbcr ycbcr = rgb2ycbcr(R, G, B); //distance float dist = uDist(ycbcr.Y, ycbcr.Cb, ycbcr.Cr, base_ycbcr[i].Y, base_ycbcr[i].Cb, base_ycbcr[i].Cr); //min dist if(dist < minDist) { minDist = dist; index = i; } } return index; } int findColsetColorIndexInYCbCr2(int R, int G, int B) { int index=-1; float minDist=1000000; for(int i=0; i< 20; ++i) { //gray scale pass if( ( (base_rgb[i].r == base_rgb[i].b) && (base_rgb[i].b == base_rgb[i].g ) ) ) continue; //rgb to ycbcr my_ycbcr ycbcr = rgb2ycbcr(R, G, B); //distance float dist = uDist2(ycbcr.Cb, ycbcr.Cr, base_ycbcr[i].Cb, base_ycbcr[i].Cr); //min dist if(dist < minDist) { minDist = dist; index = i; } } return index; } int findColsetColorIndexInRGB(int R, int G, int B) { int index=-1; float minDist=1000000; for(int i=0; i< 20; ++i) { //gray scale pass if( ( (base_rgb[i].r == base_rgb[i].b) && (base_rgb[i].b == base_rgb[i].g ) ) ) continue; //rgb to ycbcr //distance float dist = uDist(R, G, B, base_rgb[i].r, base_rgb[i].g, base_rgb[i].b); //min dist if(dist < minDist) { minDist = dist; index = i; } } return index; } hsv_color RGB2HSV(unsigned char r, unsigned char g, unsigned char b) { unsigned char rgb_min, rgb_max; rgb_min = MININ3(b, g, r); rgb_max = MAXIN3(b, g, r); hsv_color hsv; hsv.v = rgb_max; if (hsv.v == 0) { hsv.h = hsv.s = 0; return hsv; } hsv.s = 255*(rgb_max - rgb_min)/hsv.v; if (hsv.s == 0) { hsv.h = 0; return hsv; } if (rgb_max == r) { hsv.h = 0 + 43*(g - b)/(rgb_max - rgb_min); } else if (rgb_max == g) { hsv.h = 85 + 43*(b - r)/(rgb_max - rgb_min); } else /* rgb_max == rgb.b */ { hsv.h = 171 + 43*(r - g)/(rgb_max - rgb_min); } return hsv; } my_xyz HSV2Cylindric(unsigned char h, unsigned char s, unsigned char v) { my_xyz xyz; xyz.x = s*cos(2*3.1415*h/255.); xyz.y = s*sin(2*3.1415*h/255.); xyz.z = v; return xyz; } my_xyz HSV2conic(unsigned char h, unsigned char s, unsigned char v) { my_xyz xyz; xyz.x = s*cos(2*3.1415*h/255.)*v/255.; xyz.y = s*sin(2*3.1415*h/255.)*v/255.; xyz.z = v; return xyz; } my_ycbcr rgb2ycbcr(unsigned char r, unsigned char g, unsigned char b) { my_ycbcr ycbcr; ycbcr.Y = (299*r + 587*g + 114*b)/1000; //y ycbcr.Cb = 0.5643*(b - ycbcr.Y) + 128; //cb ycbcr.Cr = 0.7132*(b - ycbcr.Y) + 128; //cr return ycbcr; } float getSTDrgb(int R, int G, int B) { float std; float mean = (R+G+B)/3; std = sqrt( (R-mean)*(R-mean)+(G-mean)*(G-mean)+(B-mean)*(B-mean) ) / 3; return std; }...
No comments:
Post a Comment