2015-11-01 70 views
5

我開發Android上的一個項目,這需要我篩選多達5米不同的顏色 - 包括背景色(約計白色)。我不能使用高級數學算法,因爲我不知道太多的數學(我會完全迷失方向),但是通過一些簡單的邏輯算法,我通過反覆試驗得出了一些邏輯算法,部分是邏輯的,我已經能夠結果可以達到70%。但我需要關於如何使其100%工作的建議。需要有關調色板顏色量化:JAVA - Android電子

爲了測試這個算法,我在普通的白色(第5色)紙上用4種不同顏色的筆在隨機的單詞/字母上塗寫,並且編寫了一些代碼來解碼顏色。因此,在代碼中的算法...

  • 如果紅色筆墨像素進行解碼,像素被設置爲數字紅色
  • 如果藍色筆墨像素進行解碼,像素被設置爲數字藍色
  • 如果綠色筆墨水像素被解碼時,像素被設定爲數字綠色
  • 如果黑筆墨水像素被解碼時,像素被設定爲數字黃色

的黑色墨水像素被設定爲數字黃色(不黑,因爲黑色很難區分墨水黑色視覺)。

我的代碼如下,但首先這裏是我有的最好的結果之一。正如您所看到的,在黑色(用數字黃色表示)和紅色(用數字紅色表示)之間的邊緣會有重疊。就像我說的我的代碼是部分邏輯的部分試錯。

我的第一個問題是,我怎麼能改善這個算法,以便解碼/過濾器完美的顏色(我選擇了這種方法,因爲我得到非常複雜的數學失去了速度非常快)?

其次我怎樣才能使它適用於不同的色調(白光, 黃色光......)?

編輯:在進一步的評論和討論,我已經意識到,幫助我需要的是調色板顏色量化的Adroid Java代碼例子,由於

Undecoded Original image

Decoded image, almost but not good enough

if( (Blue > Green) &&(Red > Blue) && (Red - Green) > 25) 
    copyOfBM.setPixel(x, y, Color.RED); //red 
else if( (Blue > Red) && ((Blue > Green))) 
    copyOfBM.setPixel(x, y, Color.BLUE); 
else if((Green >= 82) && ((Green - Blue) >= 12) && 
    ((DecodeLuminaceColor(x, y, copyOfBM)>= 82) && 
    (DecodeLuminaceColor(x, y, copyOfBM)< 124)) ) 
    copyOfBM.setPixel(x, y, Color.GREEN); 
else if(((Red - Green) > 6) &&((Red - Green) < 17) &&((Green - Blue) < 8) 
    && (DecodeLuminaceColor(x, y, copyOfBM)< 118)) 
    copyOfBM.setPixel(x, y, Color.YELLOW); 



void DecodeLuminaceColor(int _x, int _y, Bitmap cBM ){ 
    float avrLum = 0; 
    Red = 0; Green = 0; Blue = 0; //Color.green(green_encoded_color); 

    red_encoded_color = cBM.getPixel(_x, _y); 
    green_encoded_color = cBM.getPixel(_x, _y); 
    blue_encoded_color = cBM.getPixel(_x, _y); 

    Red = ((red_encoded_color >> 16) & 0xff); 
    Green = ((green_encoded_color >> 8) & 0xff); 
    Blue = ((blue_encoded_color >> 0) & 0xff); 
} 
+0

「我選擇了這種方法,因爲我非常快速地輸了很複雜的數學。」我的數學比我想要的要少,但是有一些任務,整數算術只會產生近似的答案;這可能就是其中之一。 – msw

+0

我想知道'100%完美'解決方案是什麼樣子。當然,圖像的固有模糊性意味着對於某些像素,顏色無法準確確定?就此而言,迄今爲止的結果並不糟糕。 – usr2564301

+0

除了重疊解碼的結果之外,上面的代碼還有很多硬編碼(紅色像素會導致黑色的誤解碼),這就是爲什麼我認爲應該有更好的解決方案,你知道任何複雜的方法那會產生更準確的解決方案?如果願意,請分享,謝謝 – user4666

回答

4

我會用HSV色彩空間

這是更好地檢測顏色(更多人類感知等)應該有很大的幫助。您還可以使用HSV Histogram來檢測您擁有多少個不同的顏色。

HSV histogram

如果你仍然想RGB比比較不同

你有筆color0=(r0,g0,b0)和像素color=(r,g,b)所以計算它們之間的距離:

d=((r-r0)*(r-r0))+((g-g0)*(g-g0))+((b-b0)*(b-b0)) 

無需sqrt。現在你只計算d爲你(筆),每一種顏色,然後選擇最小d ...你也可以使用不太精確:

d=abs(r-r0)+abs(g-g0)+abs(b-b0) 

如果你不知道這之前的顏色和不想使用直方圖

  1. 形式的(再)色表(組不同的可見顏色,你會設置爲每次發現新筆)
  2. 創建發現顏色的空單
  3. 只處理輸入圖像
  4. 計算距離d的所有像素的所有顏色發現列表中的
  5. 如果d越小則一些treshold恆定的像素屬於在發現顏色列表的顏色。否則將它添加爲新發現的顏色。
  6. 從顏色表重新着色像素。

這將消除陰影和抗鋸齒顏色失真。您也可以忽略重新着色表並使用找到的顏色列表中的顏色。該過程的形式爲色彩量化

[EDIT1]使用HSV顏色,重新着色,以發現顏色列表(沒有直方圖)我得到這個結果後:

HSV simple recolor

這說明圖像中有不一樣的照明條件下(不一個渲染,但真正的照片)。所以Ilumination normalization應該更好地改善這一點。另外,我使用2個閾值一個用於灰度和一個用於顏色...以區分這兩個...還可以通過以下方式檢測背景顏色:

  • 像素數(應該比文本的顏色大得多)
  • 沿着圖像分散體(應該覆蓋大面積與均勻分散...文本被局部化相對高密度的)

這裏C++/VCL源出於此:

backbuffer bmp; // source and target image 
struct _color { DWORD rgb; int h,s,v; }; // color entry in (re)color table 
_color ld_rgb(DWORD rgb)     // just RGB -> HSV conversion 
    { 
    const int _b=0; 
    const int _g=1; 
    const int _r=2; 
    const int _a=3; 
    union { DWORD dd; BYTE db[4]; } c; 
    double r,g,b,min,max,del,h,s,v,dr,dg,db; 
    c.dd=rgb; 
    r=c.db[_r]; r/=255.0; 
    g=c.db[_g]; g/=255.0; 
    b=c.db[_b]; b/=255.0; 
    min=r; if (min>g) min=g; if(min>b) min=b; 
    max=r; if (max<g) max=g; if(max<b) max=b; 
    del=max-min; 
    v=max; 
    if (del<=0.1) { h=0; s=0; } // grayscale 
    else{ 
     s=del/max; 
     dr=(((max-r)/6.0)+(del/2.0))/del; 
     dg=(((max-g)/6.0)+(del/2.0))/del; 
     db=(((max-b)/6.0)+(del/2.0))/del; 
     if  (fabs(r-max)<1e-10) h=db-dg; 
     else if (fabs(g-max)<1e-10) h=(1.0/3.0)+dr-db; 
     else if (fabs(b-max)<1e-10) h=(2.0/3.0)+dg-dr; 
     if (h<0.0) h+=1.0; 
     if (h>1.0) h-=1.0; 
     } 
    _color ccc; 
    ccc.rgb=rgb; 
    ccc.h=255.0*h; 
    ccc.s=255.0*s; 
    ccc.v=255.0*v; 
    return ccc; 
    } 
void recolor() // this is the recolor you want 
    { 
    // load input jpg file to bmp image 
    TJPEGImage *jpg=new TJPEGImage(); 
    jpg->LoadFromFile("in.jpg"); 
    bmp.bmp->Assign(jpg); 
    bmp.resize(bmp.bmp->Width,bmp.bmp->Height); 
    delete jpg; 

    // recolor bmp 
    int i,x,y,d; 
    _color c0,c1; 
    List<_color> col;     // color list 
    col.num=0;       // clear colro list 
    for (y=0;y<bmp.ys;y++)    // process all pixels 
    for (x=0;x<bmp.xs;x++) 
     { 
     c0=ld_rgb(bmp.pyx[y][x]);  // pixel color -> hsv 

     if ((c0.h==0)&&(c0.s==0))  // compare it to found colors (grayscales) 
     for (i=0;i<col.num;i++) 
      { 
//   i=-1; c1.rgb=0x00202020; break; 
      c1=col[i]; 
      if ((c1.h!=0)||(c1.s!=0)) continue; 
      d=abs(c1.v-c0.v); 
      if (d<32) { i=-1; break; } // match found ? 
      } 
     else       // compare it to found colors 
     for (i=0;i<col.num;i++) 
      { 
//   i=-1; c1.rgb=0x0000FF00; break; 
      c1=col[i]; 
      if ((c1.h==0)&&(c1.s==0)) continue; 
      d=(abs(c1.h-c0.h))+(abs(c1.s-c0.s)); 
      if (d<50) { i=-1; break; } // match found ? 
      } 
     if (i>=0) { c1=c0; col.add(c1); } // if not add new color 
     bmp.pyx[y][x]=c1.rgb;    // recolor; 
     } 
    bmp.bmp->Canvas->Brush->Style=bsClear; 
    bmp.bmp->Canvas->Font->Color=0x00802040; 
    bmp.bmp->Canvas->TextOutA(5,0,"Found colors: "+AnsiString(col.num)); 
    bmp.bmp->Canvas->Brush->Style=bsSolid; 
    for (d=16,i=0;i<col.num;i++) 
    for (y=d;y<=d+d;y++) 
     for (x=d*i+1;(x<d*i+d)&&(x<bmp.xs);x++) 
     bmp.pyx[y][x]=col[i].rgb; 
    } 
  • List<T> l;是動態數組像std::vector<T> ...表示T l[l.num];
  • backbuffer bmp;是礦圖像類... bmp.bmp存放GDI位圖和bmp.xs,bmp.ys是持有發現顏色分辨率
  • col ...

[EDIT1]雙三次光照歸

我最近被重寫我的DIP LIB提升礦井照明正常化所以我給一個鏡頭在你的輸入圖像(如許多測試圖像之一)這裏的結果(強迫(檢測)空白處重新着色):

normalized image

正如你可以看到中間的紅色十歲上下的照明當場就沒了。你可以嘗試一下你的算法,這樣你就知道在編碼之前應用光照規範化是否有幫助(如果正確完成,它有點複雜)。這一個是這樣完成的:

  1. 爲你的形象

    創建網格(表)各細胞包含電池面積的平均顏色和累計三角洲(噪聲)。另外單個標誌告訴單元是否爲油墨。細胞尺寸應最小細節大小的周圍<0.5 - 1.5>(如字母或筆寬度...)

  2. 組具有高增量作爲墨剩餘部分作爲紙中的所有紙張的

  3. 計算平均顏色所有細胞細胞結合
  4. 每個紙張小區相鄰墨小區

    組作爲油墨,如果其平均顏色是從全球平均紙張顏色太遠。請注意不要將這些新設置的墨跡單元作爲此步驟的鄰居條件。 (使用溫度標記或不同的標誌位,這完成後恢復...

  5. 找到16個控制點沿着圖像均勻分散(只使用紙單元)

    他們應該在座標圖像的0%,33%,66%,100%分辨率所以雙三次插值是有效的。

  6. 每個像素

    雙立方計算單元格顏色,並調用它c0然後將規範化應用於像素(RGB空間中的):

    • pixel+=global_avg_color-c0;

    這將沿着整個圖像均衡紙張顏色,以便與global_avg_color非常接近地匹配。保持非紙質細節不失真。

  7. 任選重新着色的所有紙張的細胞面積與global_avg_color

    這不是必要的,但它會消除大部分從背景噪聲。像紙張紋理...

+0

非常感謝您的回覆。它非常有幫助。儘管我仍然試圖理解你解釋的理論。我早上做了一些,現在又重新研究了一遍。我稍後可能會有一些問題。與此同時,一個觀察....因爲我拍攝照片的圖像張貼我的相機進一步扭曲了原來的顏色時發佈..... – user4666

+0

。例如,我張貼的A4已扭曲從白色到灰色。但非常感謝您的回覆。我有一些問題...會發布一下 – user4666

+0

謝謝。首先,我如何獲得所列顏色的HSV數據?這意味着H值,S值和V值第二如何轉換爲RGB,最後可能最重要的是您的代碼是否存在Java版本,我只在Java中工作。我認爲第一個和第二個問題在那裏,但還不夠明確,我還沒有看到。非常感謝 – user4666