2016-04-24 158 views
3

在最近的項目中,我必須操作圖像,但由於這對我來說是新的,所以我迷失了方向。如何更改黑色的白色背景

我需要使用常規掃描設備掃描手。我可以做到這一點,但背景是白色的,我需要它是黑色的。經過幾天的研究找到改變顏色的方式,我只有一個圖像,似乎在ms paint中剪切和粘貼。

原始圖像:

Raw Scan of the hand

測試:

Raw Scan of the hand

我需要的是這樣的:

Target image

我嘗試使用Marvin Framework,Imagej,Catalano框架。要查看我需要的設置,我使用gimp,marving編輯器,斐濟應用程序(但沒有得到我期待的結果)。
我想我需要的是轉換爲灰度,應用某種閾值,但在一定範圍內的顏色使用alpha顏色(但我沒有找到方法,只有閾值的二進制圖像),然後應用掩碼插入使用閾值灰度圖像的原始圖像中,但我不知道如何在Java中直接執行此操作,或者使用上面提到的任何框架。
任何幫助,將不勝感激。

UPDATE 根據m69的說法,我試着打出明亮的價值,從rgb轉換爲hsl。我只設置較暗的顏色。

先用的光的0.5的閾值嘗試:

First try

第二嘗試用的光

Second try

float threshold = 0.5f; 

for(int y=0; y<imageIn.getHeight(); y++){ 
    for(int x=0; x<imageIn.getWidth(); x++){ 

     int r = imageOut.getIntComponent0(x, y); 
     int g = imageOut.getIntComponent1(x, y); 
     int b = imageOut.getIntComponent2(x, y); 
     float[] hsl = HSLColor.fromRGB(r, g, b, null); 

     if(hsl[2] >= threshold){ 
      float t = (hsl[2]-0.5f)*2f; 
      hsl[2] -= t; 
      imageOut.setIntColor(x, y, HSLColor.toRGB(hsl)); 
     } 
    } 
} 

問題0.9 AA閾值是這種方法改變所有像素的光線,理想的是隻改變物體外部的顏色。我在網上尋找一個想法,並且我發現了MartinJaník提出的用於骨科分析的論文。他建議接下來的算法:

  1. 應用高斯濾波掃描得到過濾後的圖像腳
  2. 門檻過濾圖像得到二值圖像
  3. 形態接近二進制圖像以獲得封閉的二進制圖像
  4. 對二進制圖像應用高斯濾波以獲得灰度蒙版
  5. 將該蒙版應用於腳掃描以獲得總體腳形圖像

而與此我可以得到一個結果:

Martin Janík algorithm

這是接近我想要的東西,因爲在物體顏色不感動。但是物體周圍的白色邊框仍然是一個問題。這是因爲我使用combineByMask marving插件,它只是支持二進制圖像(不只是二進制圖像,但只能掩蓋一種顏色)。我認爲需要一個新的插件來結合使用灰度圖像蒙板,當顏色在1-255的範圍內嘗試與圖像底色結合以獲得更暗或更淡的顏色(當顏色爲255時,應該離開只是基本圖像的顏色)。

這就是我所說的掩蔽灰度圖像的示例圖像:

Example image apply a mask using a binary image and a grayscale image

我想這就是我要採取的路徑。

更新2

做一些研究之後,我覺得我很接近我想要的結果。我所使用的算法是:

  1. 應用5個
  2. 轉換的對比度爲灰度圖像
  3. 應用高斯濾波器
  4. 閾值的圖像
  5. 形態接近
  6. Applay高斯濾波器再次
  7. 將此結果圖像用作原始灰度蒙版

這是結果圖像:

Result apply a grayscale mask

這是接近我想要的。在這六步中,我可以應用兩次,三次或更多次的高斯濾鏡,給出更加柔和的邊界效果,但最後總是顯示一個薄的白色邊框,因爲掃描圖像的性質(我認爲這是我可以不處理),但我很滿意這個結果。現在,因爲我沒有找到一個java算法應用於灰度蒙版,我的代碼如下:

for(int y=0; y<mask.getHeight(); y++){ 
     for(int x=0; x<mask.getWidth(); x++){ 

      //ya que está en grayscale, los 3 valores son los mismos 
      int r1 = mask.getIntComponent0(x, y); 
      int g1 = mask.getIntComponent1(x, y); 
      int b1 = mask.getIntComponent2(x, y); 

      int r2 = image.getIntComponent0(x, y); 
      int g2 = image.getIntComponent1(x, y); 
      int b2 = image.getIntComponent2(x, y); 

      //al color de salida, le asignamos la luminicencia de la imagen mascara 
      int r = 0, g = 0, b = 0; 
      if(r1 > 0 || r2 > 0){ 
       r = r1*r2/Math.max(r1, r2); 
      } 

      if(g1 > 0 || g2 > 0){ 
       g = g1*g2/Math.max(g1, g2); 
      } 

      if(b1 > 0 || b2 > 0){ 
       b = b1*b2/Math.max(b1, b2); 
      } 

      image.setIntColor(x, y, r, g, b); 
     } 
    } 

擁有近得非常好,但有一點微小的細節,我解決不了。我們的想法是在辮形我沒有圖像混合以下:具有一個上層的灰度掩模,施加顏色的α函數的白顏色,得到這樣的結果:

Gimp mix

隨着算法我寫了marving框架,我得到的下一張圖片:

Using marving

不同的是,我的算法不能低時,有一個更白的顏色原始圖像的亮度的顏色,你可以看到,效果比較2張圖片。任何想法如何處理它?這是在GIMP應用層組合後的圖像結果:

Layer combination en gimp

+0

我認爲白色邊框來自於在曲線的閾值處使用方向的突然變化,而不是像我在示例中那樣的圓角彎曲。檢查你的框架是否有任何方法來爲亮度創建樣條曲線,或者使用圓的一部分或某些東西來展開自己的樣式。 – m69

+0

如果你還在研究這個項目,並且想進一步討論,你可以在ImageJ論壇上發佈:http://forum.imagej.net/。有相當多的圖像處理專家可能會對你的分析提供建議和努力。 – ctrueden

回答

2

最好的辦法是進入照相館或GIMP,你想要什麼使用快速蒙板功能塗料或縮小,你可以得到非常詳細的像素,然後退出快速蒙版模式,並確保白色是你的行軍螞蟻周圍的部分,並從那裏刪除它繼續前進,填充一層黑色背景。您可能會在邊緣使用輕微的羽毛來自然融合。有關於如何做到這一點的更具體的教程,但這是我將如何處理它。

+0

感謝您的回答,但我需要軟件自動執行。 –

1

您應該首先將RGB轉換爲HSL(色調,飽和度,亮度/亮度),然後對亮度應用曲線,以便超過某個亮度(太亮)的值再次逐漸回到黑色。到底哪個點亮度應該跟隨對角線在下降之前取決於照片的亮度和對比度。 (我猜這可能是圖形框架標準功能)

以下是應用於亮度展示的那種結果的曲線的兩個例子中你會得到:

enter image description here enter image description here

2

該方法取決於您的分析目的。第一種方法會影響整個圖像,因此手掌的紋理會發生變化!第二種方法隻影響手邊界!

這兩種方法都是使用Marvin Image Processing Framework開發的。

INPUT:

enter image description here

阿布羅奇1:

如sugested由用戶M69,基於所述灰度值的顏色改造的探討。

輸出:

enter image description here

來源:

import marvin.image.MarvinImage; 
import marvin.io.MarvinImageIO; 

public class ScanTest { 
    public static void main(String[] args) { 
     MarvinImage image = MarvinImageIO.loadImage("./res/scan.jpg"); 
     int r,g,b; 
     for(int y=0; y<image.getHeight(); y++){ 
      for(int x=0; x<image.getWidth(); x++){ 
       r = image.getIntComponent0(x, y); 
       g = image.getIntComponent1(x, y); 
       b = image.getIntComponent2(x, y); 

       int gray = (int)((0.22*r)+(0.7*g)+(0.08*b)); 
       double t = transform(gray, 1.3); 
       image.setIntColor(x, y, (int)(r*t), (int)(g*t), (int)(b*t));  
      } 
     } 
     MarvinImageIO.saveImage(image, "./res/scan_out.jpg");  
    } 

    private static double transform(int gray, double brightness){ 
     if(gray < 127){ 
      return brightness; 
     } 
     else{ 
      return (1-((double)(gray-127)/128))*brightness; 
     } 
    } 
} 

的形式給出了2:

您可以使用HSV科洛爾模型來加深IMAG的明亮區域考慮一些飽和度和價值閾值。這種方法不會影響手掌的質感。

輸出:

enter image description here

來源:

public class ScanTest { 
    public static void main(String[] args) { 
     MarvinImage image = MarvinImageIO.loadImage("./res/scan.jpg"); 
     int r,g,b; 
     int rgb[] = new int[1]; 
     double hsv[]; 
     for(int y=0; y<image.getHeight(); y++){ 
      for(int x=0; x<image.getWidth(); x++){ 
       r = image.getIntComponent0(x, y); 
       g = image.getIntComponent1(x, y); 
       b = image.getIntComponent2(x, y); 
       rgb[0] = image.getIntColor(x, y); 
       hsv = MarvinColorModelConverter.rgbToHsv(rgb); 

       if(r >= 235 && g >= 235 && b >=235){ 
        image.setIntColor(x, y, 0,0,0); 
       } 
       else if(hsv[1] <= 0.12 && hsv[2] >= 0.6){ 
        double diff = 1-hsv[2]; 
        if(diff > 0.02){ 
         diff = Math.max(diff,0.2); 
        } 
        diff*=3; 
        image.setIntColor(x, y, (int)(r*diff), (int)(g*diff*0.75), (int)(b*diff*0.75)); 
       } 
      } 
     } 
     MarvinImageIO.saveImage(image, "./res/scan_out.jpg");  
    } 
} 
0

這似乎是一個非常愚蠢的建議,但你可以掃描你的手與掃描儀蓋子打開?您有白色背景的唯一原因是掃描儀的內蓋是白色的,並且反射了掃描儀本身的光線。如果您打開蓋子並在黑暗的房間內掃描手,則應該有非常接近您參考的腳照片的效果。

不是一種軟件解決方案,但它可能會讓你更接近你想要的結果。它也可以幫助你的指數和中指過飽和。

+0

沒有人,嘴脣仍然開着,仍然用白色背景掃描,但感謝你的adivce。 –

+0

這很奇怪,我昨天晚上用掃描儀進行了測試,結果很有效。你是否在黑暗的房間裏打開蓋子進行掃描?我今晚晚些時候會發布我的一些照片。 –