如何更改黑色

时间:2016-04-24 00:06:36

标签: java algorithm image-processing imagej marvin-framework

在最近的一个项目中,我不得不操纵图像,但由于这对我来说是新的,我有点迷失。

我需要使用常规扫描设备扫描手。我可以完成这个,但背景是白色的,我需要它是黑色的。经过几天的研究找到了改变颜色的方法,我只得到了一个看起来像是用油漆修剪和粘贴的图像。

原始图片:

Raw Scan of the hand

测试:

Raw Scan of the hand

我需要的是这样的事情:

Target image

我尝试使用Marvin FrameworkImagejCatalano框架。要查看我需要的设置,我使用gimp,marving editor,fiji app(但没有得到我想要的结果)。
我认为我需要的是转换为灰度,应用某种阈值,但在一定范围的颜色中使用alpha颜色(但我没有找到方法,只有二进制图像的阈值),然后应用一个掩码到原来使用阈值灰度图像,但我不知道怎么做,直接在Java中,或使用我上面提到的任何框架。
任何帮助将不胜感激。

更新 根据m69的说法,我尝试使用发光值,从rgb转换为hsl。我只设置了较暗的颜色。

首先尝试使用0.5的光阈值:

First try

第二次尝试使用0.9的光阈值

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));
        }
    }
}

问题是这种方法改变了所有像素的光线,理想的是只改变对象外部的颜色。我在互联网上寻找一个想法,我找到了MartinJaník关于矫形分析的论文。他提出了下一个算法:

  1. 对脚部扫描应用高斯滤波以获得滤波图像
  2. 阈值滤波后的图像以获取二进制图像
  3. 形态学上关闭二进制图像以获得闭合的二进制图像
  4. 对二进制图像应用高斯滤波以获得灰度掩模
  5. 将此蒙版应用于脚部扫描以获得整体足部图像
  6. 有了这个,我可以得到下一个结果:

    Martin Janík algorithm

    这接近我想要的,因为物体中的颜色没有被触及。但仍有一个问题是物体周围的白色边框。这是因为我使用的是combineByMask marving插件,它只支持二进制图像(不仅仅是二进制图像,而且只能掩盖一种颜色)。我认为需要一个新的插件来组合使用灰度图像蒙版,当颜色在1-255范围内时尝试组合到图像基础以获得更暗或变亮的颜色(当颜色为255时,它应该离开,它应该离开只是基本图像的颜色。)

    这是我所说的掩盖灰度图像的示例图像:

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

    我认为这是我要走的路。

    更新2

    经过一些研究,我认为我接近我想要的结果。我使用的算法是:

    1. 应用五个
    2. 的对比度
    3. 转换为灰色图片
    4. 应用高斯滤波器
    5. 阈值图像
    6. 形态关闭
    7. 再次使用高斯滤镜
    8. 将此结果图像用作原始
    9. 的灰度蒙版

      这是结果图片:

      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一样混合图像,我做了以下操作:在上层使用灰度蒙版,将颜色应用于alpha函数到白色,得到这个结果:

      Gimp mix

      使用我为marving框架编写的算法,我得到下一个图像:

      Using marving

      不同之处在于,当原始图像上有更多白色时,我的算法不能降低强度颜色,您可以看到比较2个图像的效果。知道怎么处理吗?这是在gimp:

      中应用图层组合后的图像结果

      Layer combination en gimp

4 个答案:

答案 0 :(得分:2)

你最好的选择是进入照相馆或GIMP并使用快速遮罩功能进出你想要的颜色,然后你可以非常详细地看到像素然后退出快速遮罩模式并确保白色是部分你的行进蚂蚁在附近并从那里删除它继续填充一层黑色与背景。您可以在边缘使用轻微的羽毛自然地混合它。有关如何执行此操作的更具体的教程,但这就是我将如何处理它。

答案 1 :(得分:2)

该方法取决于分析的目的。第一种方法会影响整个图像,因此手掌的纹理会发生变化!第二种方法只影响手边界!

这两种方法都是使用Marvin Image Processing Framework开发的。

INPUT:

enter image description here

APROACH 1:

由用户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;
        }
    }
}

APROACH 2:

考虑到某些饱和度和值阈值,您可以使用HSV collor模型使图像的明亮区域变暗。这种方法不会影响手掌的质地。

<强>输出:

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");       
    }
}

答案 2 :(得分:1)

您应该首先将RGB转换为HSL(色调,饱和度,亮度/亮度),然后对亮度应用曲线,使高于某一级别(太亮)的值再次逐渐变回黑色。在下降之前亮度应该跟随对角线到底在哪个点取决于照片的亮度和对比度。 (我猜这些可能是图形框架中的标准功能。)

以下是应用于亮度的两个曲线示例,以说明您获得的结果类型:

enter image description here enter image description here

答案 3 :(得分:0)

这可能看起来像是一个非常愚蠢的建议,但你可以用扫描仪盖子扫开你的手吗?您拥有白色背景的唯一原因是因为扫描仪的内盖是白色的并且反射来自扫描仪本身的光。如果你打开盖子并在黑暗的房间里扫描你的手,你的效果应该非常接近你所引用的脚的照片。

不是软件解决方案,但可能会让您更接近您想要的结果。它还可以帮助你的食指和中指过饱和。