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.
UPDATE Based 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: