问题描述
在最近的一个项目中,我必须操纵图像,但由于这对我来说是新的,我有点迷失。
我需要使用常规扫描手扫描设备。我可以做到这一点,但背景是白色的,我需要它是黑色的。经过几天的研究找到了改变颜色的方法,我只得到了一个看起来像是在油漆中剪切和粘贴的图像。
原始图片:
测试:
我需要的是这样的:
我尝试使用
第二次尝试使用0.9的光阈值
浮动阈值= 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关于矫形分析的论文。他提出了下一个算法:
- 将高斯过滤应用于脚扫描以获得过滤后的图像
- 阈值滤波后的图像获取二进制图像
- 形态学上关闭二进制图像以获得封闭的二进制图像
- 将高斯滤波应用于二进制图像以获得灰度面具
- 将此面具应用于脚部扫描以获得整体足部图像
并使用此功能我可以得到下一个结果:
这个接近我想要的,因为没有触及对象中的颜色。但仍有一个问题是物体周围的白色边框。这是因为我使用的是combineByMask marving插件,它只支持二进制图像(不仅仅是二进制图像,而且只能掩盖一种颜色)。我认为需要一个新的插件来使用灰度图像蒙版进行组合,当颜色在1-255范围内时,尝试将图像基础组合以获得更暗或更亮的颜色(当颜色为255时,它应该离开只是基本图像的颜色。)
这是我所说的掩盖灰度图像的示例图像:
应用蒙版
我认为这是我要去的路径接受。
更新2
在做了一些研究后,我想我是接近我想要的结果。我使用的算法是:
- 应用五个对比
- 转换为灰色图像
- 应用高斯滤波器
- 阈值图像
- 形态关闭
- 再次使用高斯滤镜
- 将此结果图像用作原始的灰度蒙版
这是结果图像:
使用我为marving框架编写的算法,我得到下一张图片:
区别在于我的算法不能降低强度颜色原始图像上的白色更多,您可以看到比较2个图像的效果。知道怎么处理吗?这是在gimp中应用图层组合后的图像结果:
该方法取决于分析的目的。第一种方法会影响整个图像,因此手掌的纹理会发生变化!第二种方法只影响手边界!
这两种方法都是使用
APROACH 1:
由用户m69提取,基于灰度值的颜色变换。
输出:
来源:
import marvin.image.MarvinImage;
import marvin.io.MarvinImageIO;
公共类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,./ sts / scan_out.jpg);
}
私有静态双变换(int灰色,双亮度){
if(灰色< 127){
返回亮度;
}
else {
return(1 - ((double)(gray-127)/ 128))* brightness;
}
}
}
APROACH 2:
考虑到某些饱和度和值阈值,您可以使用HSV collor模型使图像的明亮区域变暗。这种方法不会影响手掌的质地。
输出:
来源:
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,./ sts / scan_out.jpg);
}
}
In a recent project I have to manipulate images, but since this is new to me I am kind of lost.
I need to scan the hand using a regular scan device. I could acomplish this but the background is white and I need it to be black. After several days of research finding the way to change the color, I only got an image that seems cut and paste in ms paint.
The original image:
Test:
What I need is something like this:
I trying using Marvin Framework, Imagej, Catalano framework. To see the setps that I need I use gimp, marving editor, fiji app (but without getting the result I was looking for).
I think what I need is to convert to gray scale, apply some sort of threshold but in a certain range of colors use alpha colors (but I did not find the way, only threshold for binary images), and then apply a mask into the original using the threshold grayscaled image, but again I don't know how to do that, in Java directly, or using any of the frameworks I mentioned above.
Any help would be appreciated.
UPDATEBased on what m69 said, i tried playing whith luminiscent value, converting from rgb to hsl. I only set darker colors which were lighten.
First try with a threshold of 0.5 of light:
Second try with a a threshold of 0.9 of light
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));
}
}
}
The problem is that this approach changes the light of all pixels, the ideal is to change only color outside of the object. I was looking for a ideas on the internet and i found a thesis by Martin Janík for orthopaedic analisis. He proposes the next algorithm:
- apply Gaussian filtering to the feet scan to get filtered image
- threshold the filtered image to get binary image
- morphologically close the binary image to get closed binary image
- apply Gaussian filtering to the binary image to get grayscale mask
- apply this mask to the feet scan to get overall foot image
And with this i can get the next result:
And this is close to what i want, because colors in the object are not touched. But still one problem the white border around the object. This is because i am using combineByMask marving plugin and it just support binary images (well not just binary images but only can mask one color). I think a new plugin is needed to combine using a grayscale image mask, when the color were in the range 1-255 try to combine to the image base to get a darker or lighten color (obiously when the color is 255, it should leave just the color of the base image).
This is an example image of what i am talking about masking grayscale images:
I think this is the path i am going to take.
UPDATE 2
After doing some research, i think i am close to the result i want. The algorithm i used was:
- Apply a contrast of five
- Convert to gray image
- Apply gaussian filter
- Threshold the image
- Morphological close
- Applay a gaussian filter again
- Use this result image as a grayscale mask to the original
This is the result image:
This is close to what i want. In the six step i could apply two, three or more times a gaussian filter, given a more soft border effect, but in the end a thin white border is always displayed because of the nature of scanned image (i think this is something i can not deal with) but i am comfortable with this result. Now as i did not found a java algorithm to apply a grayscale mask, i code this:
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);
}
}
And work almost very well, but with a little tiny detail that i can not resolve. The idea is to mix the images as in gimp i did the following: having the grayscale mask in a upper layer, apply a color to alpha function to the white color, give this result:
With the algorithm i wrote for marving framework, i get the next image:
The difference is that my algorithm can not low the intensity color when there is a more white color on the original image, you can see that effect comparing the 2 images. Any idea how to deal with it? This is the image result after applying the layer combination in gimp:
The approach depends on the purpose of your analysis. The first approach affects the entire image, therefore the texture of the palm of the hand is changed! The second approach only affects the hand border!
The both approaches were developed using Marvin Image Processing Framework.
INPUT :
APROACH 1:
As sugested by user m69, a color tranformation based on the gray scale values.
output:
source:
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:
You can use HSV collor model to darken bright areas of the image considering some saturation and value threshold. This approach does not affect the texture of the palm of the hand.
output:
source:
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");
}
}
这篇关于如何更改黑色的白色背景的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!