I am trying to create an effect similar to Sin City or other movies where they remove all colors except one from an image.
I have an RGB image which I want to convert to grayscale but I want to keep one color.
This is my picture: Image to edit
I want to keep the red color. The rest should be grayscale.
Here is my code so far:
package poza;
import java.io.*;
public class poza {
public static void main(String[] args) {
try {
FileInputStream fis=new FileInputStream("poza.bmp");
BufferedInputStream dis=new BufferedInputStream(fis);
FileOutputStream sif=new FileOutputStream("poza1.bmp");
BufferedOutputStream bos=new BufferedOutputStream(sif);
byte[] sti=new byte[54];
dis.read(sti,0,54);
bos.write(sti);
while(dis.available()>0)
{
int b,g,r;
b=dis.read();
g=dis.read();
r=dis.read();
System.out.print(b+" "+g+" "+r+"\n");
int gri=(int)(0.114*b+0.587*g+0.299*r);
if(r>=b && r>=g)
{
bos.write(gri);
bos.write(gri);
bos.write(r);
}
else
{
bos.write(b);
bos.write(g);
bos.write(r);
}
System.out.print(b+" "+g+" "+r+"\n");
}
dis.close();
bos.close();
}
catch(Exception e)
{
System.out.println(e);
}
}
}
You need to note that every color is represented by 3 values or channels, i.e. red, green and blue. If you only keep one of those channels you'll skew the results.
Instead you need to decide whether a pixel should retain its original color or become grayscale. So assuming your code already does the conversion to grayscale correctly, it comes down to this:
if( keepColor ) {
//I'll keep the order of the components that your example uses, make sure this is correct
bos.write(b);
bos.write(g);
bos.write(r);
} else {
bos.write(gri); //b
bos.write(gri); //g
bos.write(gri); //r
}
So what is left is how keepColor
is defined and that depends on your requirements. A simple option might be to pick a color and check if the pixel is within a certain threshold of that color, e.g. like this:
/**
* value - the value to check
* base - the base value to check against, i.e. the center of the range, expressed in range [0, 255]
* difference - the allowable difference in percent, expressed in range [0.0, 1.0]
*/
boolean withinThreshold(int value, int base, double difference) {
return value>= base * (1-difference) //check lower bound
&& value <= base * (1+difference); //check upper bound
}
Then pick a value and a difference, e.g. like this:
boolean keepColor = withinThreshold(r, 228, 0.6) //40%-160% of 228
&& withinThreshold(g, 95, 0.6) //40%-160% of 95
&& withinThreshold(b, 78, 0.6); //40%-160% of 78
Of course there are many other possibilities you can play around with, i.e. different thresholds, different colors, based on brightness (grayscale value in a certain range) etc.