2013-03-23 3 views
1

저는 컬러 매칭을 통해 이미지 검색 시스템을 구현해야하는 C++ 및 openFrameworks 프로그램을 작성하고 있습니다. 데이터베이스에서 rgb 값으로 일치하는 것을 찾는 알고리즘이 있습니다. 예를 들어 내 컴퓨터에 1000 개의 그림으로 된 데이터베이스가 있고 쿼리 rgb 값이 255,0,0이면이 프로그램은 1000 개의 그림을보고 가장 가까운 항목을 찾습니다. 그러나 내 문제는 웹에서 일치하는 항목을 찾으려는 것입니다. 나는 웹 사이트에서 이미지를 가져 오는 방법을 찾으려고 노력했지만 이미지의 특정 URL을 모르면 데이터를 확보하기가 어렵습니다. 어쩌면 누군가가 웹 사이트에서 이미지를 잡는 방법에 대한 지식을 가지고 있을까요? 이상적으로 프로그램은 지정된 웹 사이트로 이동하여 이미지의 모든 웹 페이지를 검색하고 각 이미지를 쿼리와 비교하여 가장 가까운 일치 항목을 출력합니다.openframeworks와 함께 C++을 사용하여 웹에서 컬러 이미지 검색 시스템

+0

으로도 제공됩니다. Flickr 및 Google 이미지 검색은 API를 통해 색상별로 데이터베이스를 검색합니다. 어떤 사이트에서든 그렇게하고 싶다면 L * a * b * 색상 공간에서 이미지와 그 평균 색상을 색인하여 자신의 작은 데이터베이스를 만들어야 할 수도 있습니다. 올바르게 기억하면 RGB에서 CIE XYZ로 변환 한 다음 L * a * b *로 변환해야합니다. 그 이유는 L * a * b * 색 공간에서 유클리드 거리를 얻을 수 있기 때문에 입력 색상에서 가장 가까운 거리 (최단 거리)까지의 최단 거리를 찾는 방법입니다. –

답변

1

내가 언급 한 것처럼 RGB 색 공간을 L b * 색 공간으로 변환하고 유클리드 거리를 데이터베이스의 이미지 평균 색상으로 변환하는 문제입니다.

여기에 기본 데모입니다 : image search by colour

#include "testApp.h" 

//ported from http://cookbooks.adobe.com/post_Useful_color_equations__RGB_to_LAB_converter-14227.html 
struct Color{ 
    float R,G,B,X,Y,Z,L,a,b; 
}; 

#define REF_X 95.047; // Observer= 2°, Illuminant= D65 
#define REF_Y 100.000; 
#define REF_Z 108.883; 

Color rgb2xyz(int R,int G,int B){ 
    float r = R/255.0; 
    float g = G/255.0; 
    float b = B/255.0; 

    if (r > 0.04045){ r = pow((r + 0.055)/1.055, 2.4); } 
    else { r = r/12.92; } 
    if (g > 0.04045){ g = pow((g + 0.055)/1.055, 2.4); } 
    else { g = g/12.92; } 
    if (b > 0.04045){ b = pow((b + 0.055)/1.055, 2.4); } 
    else { b = b/12.92; } 

    r = r * 100; 
    g = g * 100; 
    b = b * 100; 
    //Observer. = 2°, Illuminant = D65 
    Color xyz; 
    xyz.X = r * 0.4124 + g * 0.3576 + b * 0.1805; 
    xyz.Y = r * 0.2126 + g * 0.7152 + b * 0.0722; 
    xyz.Z = r * 0.0193 + g * 0.1192 + b * 0.9505; 
    return xyz; 
} 
Color xyz2lab(float X,float Y, float Z){ 
    float x = X/REF_X; 
    float y = Y/REF_X; 
    float z = Z/REF_X; 

    if (x > 0.008856) { x = pow(x , .3333333333f); } 
    else { x = (7.787 * x) + (16/116.0); } 
    if (y > 0.008856) { y = pow(y , .3333333333f); } 
    else { y = (7.787 * y) + (16/116.0); } 
    if (z > 0.008856) { z = pow(z , .3333333333f); } 
    else { z = (7.787 * z) + (16/116.0); } 

    Color lab; 
    lab.L = (116 * y) - 16; 
    lab.a = 500 * (x - y); 
    lab.b = 200 * (y - z); 
    return lab; 
} 
Color lab2xyz(float l, float a, float b){ 
    float y = (l + 16)/116; 
    float x = a/500 + y; 
    float z = y - b/200; 

    if (pow(y , 3) > 0.008856) { y = pow(y , 3); } 
    else { y = (y - 16/116)/7.787; } 
    if (pow(x , 3) > 0.008856) { x = pow(x , 3); } 
    else { x = (x - 16/116)/7.787; } 
    if (pow(z , 3) > 0.008856) { z = pow(z , 3); } 
    else { z = (z - 16/116)/7.787; } 

    Color xyz; 
    xyz.X = x * REF_X; 
    xyz.Y = y * REF_Y; 
    xyz.Z = z * REF_Z; 
    return xyz; 
} 
Color xyz2rgb(float X,float Y,float Z){ 
    //X from 0 to 95.047  (Observer = 2°, Illuminant = D65) 
    //Y from 0 to 100.000 
    //Z from 0 to 108.883 
    X = ofClamp(X, 0, 95.047); 

    float x = X * .01; 
    float y = Y * .01; 
    float z = Z * .01; 

    float r = x * 3.2406 + y * -1.5372 + z * -0.4986; 
    float g = x * -0.9689 + y * 1.8758 + z * 0.0415; 
    float b = x * 0.0557 + y * -0.2040 + z * 1.0570; 

    if (r > 0.0031308) { r = 1.055 * pow(r , (1/2.4f)) - 0.055; } 
    else { r = 12.92 * r; } 
    if (g > 0.0031308) { g = 1.055 * pow(g , (1/2.4f)) - 0.055; } 
    else { g = 12.92 * g; } 
    if (b > 0.0031308) { b = 1.055 * pow(b , (1/2.4f)) - 0.055; } 
    else { b = 12.92 * b; } 

    Color rgb; 
    rgb.R = round(r * 255); 
    rgb.G = round(g * 255); 
    rgb.B = round(b * 255); 
    return rgb; 
} 
Color rgb2lab(int R,int G,int B){ 
    Color xyz = rgb2xyz(R, G, B); 
    return xyz2lab(xyz.X, xyz.Y, xyz.Z); 
} 
Color lab2rgb(int L,int a,int b){ 
    Color xyz = lab2xyz(L, a, b); 
    return xyz2rgb(xyz.X, xyz.Y, xyz.Z); 
} 

Color getAverage(ofImage img){ 
    Color avg; 
    avg.L = avg.a = avg.b = 0; 

    int total = img.width * img.height; 
    for(int y = 0 ; y < img.height; y++){ 
     for(int x = 0 ; x < img.width; x++){ 
      ofColor c = img.getColor(x, y); 
      Color lab = rgb2lab(c.r,c.g,c.b); 
      avg.L += lab.L; 
      avg.a += lab.a; 
      avg.b += lab.b; 
     } 
    } 

    avg.L /= total; 
    avg.a /= total; 
    avg.b /= total; 
    return avg; 
} 
ofImage images[6]; 
Color averages[6]; 
ofColor averagesRGB[6]; 

ofImage colorPicker; 
ofColor searchClr; 

int closestId = -1; 

//-------------------------------------------------------------- 
void testApp::setup(){ 
    colorPicker.loadImage("colormap.gif"); 

    images[0].loadImage("red.jpg"); 
    images[1].loadImage("green.jpg"); 
    images[2].loadImage("blue.jpg"); 
    images[3].loadImage("cyan.jpg"); 
    images[4].loadImage("magenta.jpg"); 
    images[5].loadImage("yellow.jpg"); 

    for(int i = 0 ; i < 6; i++){ 
     averages[i] = getAverage(images[i]); 
     Color avgRGB = lab2rgb(averages[i].L, averages[i].a, averages[i].b); 
     averagesRGB[i] = ofColor(avgRGB.R,avgRGB.G,avgRGB.B); 
    } 

} 

//-------------------------------------------------------------- 
void testApp::update(){ 
    //pick a colour 
    searchClr = colorPicker.getColor(mouseX,mouseY-500); 
    //find closest - might want to that on an event 
    Color searchLab = rgb2lab(searchClr.r, searchClr.g, searchClr.b); 
    float minDist = 10000000; 
    for(int i = 0 ; i < 6; i++){ 
     Color Lab = averages[i]; 
     float dL = Lab.L - searchLab.L; 
     float da = Lab.a - searchLab.a; 
     float db = Lab.b - searchLab.b; 
     float dist = sqrt(dL*dL + da*da + db*db); 
     if(dist < minDist){ 
      minDist = dist; 
      closestId = i; 
     } 
    } 
} 

//-------------------------------------------------------------- 
void testApp::draw(){ 
    for(int i = 0 ; i < 6; i++){ 
     //indexed image 
     images[i].draw(images[i].width * i, 0); 
     //average colour 
     ofPushStyle(); 
     ofSetColor(averagesRGB[i]); 
     ofRect(images[i].width * i, images[i].height, images[i].width, images[i].width); 
     ofPopStyle(); 
    } 
    ofPushStyle(); 
    ofSetColor(searchClr); 
    ofRect(200,500,200,200); 
    ofPopStyle(); 
    colorPicker.draw(0,500); 
    if(closestId >= 0){ 
     images[closestId].draw(400, 500); 
    } 
} 

//-------------------------------------------------------------- 
void testApp::keyPressed(int key){ 

} 

//-------------------------------------------------------------- 
void testApp::keyReleased(int key){ 

} 

//-------------------------------------------------------------- 
void testApp::mouseMoved(int x, int y){ 

} 

//-------------------------------------------------------------- 
void testApp::mouseDragged(int x, int y, int button){ 

} 

//-------------------------------------------------------------- 
void testApp::mousePressed(int x, int y, int button){ 

} 

//-------------------------------------------------------------- 
void testApp::mouseReleased(int x, int y, int button){ 

} 

//-------------------------------------------------------------- 
void testApp::windowResized(int w, int h){ 

} 

//-------------------------------------------------------------- 
void testApp::gotMessage(ofMessage msg){ 

} 

//-------------------------------------------------------------- 
void testApp::dragEvent(ofDragInfo dragInfo){ 

} 

코딩 스타일은 화려한 아니지만 그냥 아이디어를 설명 할 수있다. 물론 URL에서 이미지를로드하고 L 의 평균 색을 데이터베이스 (런타임시 또는 다른 방법으로 벡터)에 각각 b * 색인으로 생성해야합니다. 위 코드는 Xcode project