Here is my code for converting a png image to binary image form.Although sometime it convert one image to binary image form but on some other time it convert it to binary image form with image rotated to some angle..here buffered image is the input png image that i wana convert to binary form
public static byte[][] binarizeImage(BufferedImage bfImage){
final int THRESHOLD = 160;
int height = bfImage.getHeight();
int width = bfImage.getWidth();
byte[][] image = new byte[width][height];
for(int i=0; i<width; i++){
for(int j=0; j<height; j++){
Color c = new Color(bfImage.getRGB(i,j));
int red = c.getRed();
int green = c.getGreen();
int blue = c.getBlue();
if(red<THRESHOLD && green<THRESHOLD && blue<THRESHOLD){
image[i][j] = 1;
}else{
image[i][j] = 0;
}
}
}
return image;
}
can anyone pls tel the problem.for some images it works for other it doesnt.i making use of getrgb function
EDIT: Just improving legibility.
Related
In my android app, I have a car from which the user can click and select different panels. The image is relatively complicated (as opposed to the one pasted here) so its difficult to overlay the buttons in the correct spots. In addition there are a lot of different images.
The solution I would like to try:
Detect which panel was selected by using a colour mask as suggested here: https://blahti.wordpress.com/2012/06/26/images-with-clickable-areas/
Depending on the panels selected (in my example the blue and green) generate a mask.
Depending on the mask, have a red overlay on the car - just a colour filter will be fine.
(First image represents the colours used to determine which panel was clicked, second image represents the mask generated and the last image the 'result').
The only problem I'm having is: How do I dynamically create the mask? I thought of using a floodfill type method to create a new canvas with the 'mask' of the selected panels. But, I worry that it might be too computationally heavy. Any simpler suggestions?
[
UPDATE: Ok so I've come pretty far. As expected, the creation of the mask too way too long (2-4 seconds for a small image). But, then I discovered RenderScripts!! I think I can still get this to work. The only little snag that I have now is: How do I pass in the colours that have been pressed?
My current code looks like this:
// create a bitmap for the mask.
ImageView img = (ImageView) findViewById (mask);
img.setDrawingCacheEnabled(true);
Bitmap bitmap = Bitmap.createBitmap(img.getDrawingCache());
// Create a tiny bitmap to store the colours of the panels that are
//'selected'
Bitmap.Config conf = Bitmap.Config.ARGB_8888; // see other conf types
Bitmap myBitmap = Bitmap.createBitmap(pickedPanels.size(), 1, conf);
int [] myInts = new int[pickedPanels.size()];
for (int i = 0; i<pickedPanels.size(); i++){
myInts[i] = pickedPanels.get(i).intValue();
}
myBitmap.setPixels(myInts, 0, myBitmap.getWidth(), 0, 0,
myBitmap.getWidth(),0);
//Run thescript and set the output
final RenderScript rs = RenderScript.create(this);
final Allocation input = Allocation.createFromBitmap(rs, bitmap,
Allocation.MipmapControl.MIPMAP_NONE,Allocation.USAGE_SCRIPT);
final Allocation output = Allocation.createTyped(rs, input.getType());
final ScriptC_singlesource script = new
ScriptC_singlesource(rs);
script.set_image(Allocation.createFromBitmap(rs, myBitmap,
Allocation.MipmapControl.MIPMAP_NONE,Allocation.USAGE_SCRIPT));
script.set_imgWidth(pickedPanels.size());
script.forEach_root(input, output);
output.copyTo(bitmap);
img.setImageBitmap(bitmap);
ImageView destim = (ImageView) findViewById (dest);
destim.setDrawingCacheEnabled(true);
destim.setImageBitmap(bitmap);
and this is the script:
#pragma version(1)
#pragma rs java_package_name(za.co.overtake)
rs_allocation image;
int imgWidth;
uchar4 RS_KERNEL root(uchar4 in, uint32_t x, uint32_t y) {
for(int col = 0; col < imgWidth; col++){
const uchar4 colour = *(const uchar4*)rsGetElementAt(image, col,0);
if (in.r == colour.r && in.g == colour.g && in.b == colour.b){
in.r = 255;
in.g = 0;
in.b = 0;
break;
} else {
in.r = 0;
in.g = 255;
in.b = 0;
rsDebug("HELLLLLP>>", colour);
}
}
return in;
}
But, when I try and read the pixel values from myBitmap (or image in the script), RGB is always 0.
(Sorry for the bad naming, etc. I've been going crazy trying to figure this out)
Ok, finally got this figured out.
In my renderscript code I have:
#pragma version(1)
#pragma rs java_package_name(za.co.overtake)
int*reds;
int*greens;
int*blues;
int imgWidth;
uchar4 RS_KERNEL root(uchar4 in, uint32_t x, uint32_t y) {
bool colourme = false;
for(int col = 0; col < imgWidth; col++){
const int red = reds[col];
const int green = greens[col];
const int blue = blues[col];
if (in.r == red && in.g == green && in.b == blue){
colourme = true;
}
}
if (colourme) {
in.r = 255;
in.g = 0;
in.b = 0;
in.a = 50;
} else {
in.r = 0;
in.g = 0;
in.b = 0;
in.a = 0;
}
return in;
}
Then in Java
public void showDamagedPanels(int dest, int mask) {
int noOfColours = pickedPanels.size();
if (noOfColours > 0) {
ImageView img = (ImageView) findViewById (mask);
img.setDrawingCacheEnabled(true);
Bitmap bitmap = Bitmap.createBitmap(img.getDrawingCache());
img.setDrawingCacheEnabled(false);
int [] reds = new int[noOfColours];
int [] greens = new int[noOfColours];
int [] blues = new int[noOfColours];
for (int i = 0; i< noOfColours; i++){
int colour = pickedPanels.get(i);
reds[i] = (colour >> 16) & 0xFF;
greens[i] = (colour >> 8) & 0xFF;
blues[i] = (colour >> 0) & 0xFF;
}
final RenderScript rs = RenderScript.create(this);
final Allocation input = Allocation.createFromBitmap(rs, bitmap, Allocation.MipmapControl.MIPMAP_NONE,
Allocation.USAGE_SCRIPT);
final Allocation output = Allocation.createTyped(rs, input.getType());
final ScriptC_singlesource script = new ScriptC_singlesource(rs);
Allocation red = Allocation.createSized(rs, Element.I32(rs), reds.length);
red.copyFrom(reds);
script.bind_reds(red);
Allocation green = Allocation.createSized(rs, Element.I32(rs), greens.length);
green.copyFrom(greens);
script.bind_greens(green);
Allocation blue = Allocation.createSized(rs, Element.I32(rs), blues.length);
blue.copyFrom(blues);
script.bind_blues(blue);
script.set_imgWidth(pickedPanels.size());
script.forEach_root(input, output);
output.copyTo(bitmap);
ImageView destim = (ImageView) findViewById (dest);
destim.setDrawingCacheEnabled(true);
destim.setImageBitmap(bitmap);
} else {
ImageView destim = (ImageView) findViewById (dest);
destim.setImageBitmap(null);
}
}
where dest is the overlay image and mask in the image acting as the mask. So basically, when a panel is clicked - place its colour in pickedPanels. Then call the showPanels method, which calls the script. The script checks the colours and sets the resulting image red or clear.
Update: For anyone trying to use this, but having some issues: It is possible to do this without the renderscript code, but it does run a bit slower - though it has been ok in my case for small images.
private Bitmap changeColor(Bitmap src, Set<Integer> pickedPanelsList) {
int fine = getResources().getColor(R.color.colorAccent);
int width = src.getWidth();
int height = src.getHeight();
int[] pixels = new int[width * height];
// get pixel array from source
src.getPixels(pixels, 0, width, 0, 0, width, height);
Bitmap bmOut = Bitmap.createBitmap(width, height, src.getConfig());
int AGood = 100, RGood = Color.red(fine), GGood = Color.green(fine), BGood = Color.blue(fine);
int ABad = 100, RBad = Color.red(Color.RED), GBad = Color.green(Color.RED), BBad = Color.blue(Color.RED);
int pixel;
// iteration through pixels
for (int y = 0; y < height; ++y) {
for (int x = 0; x < width; ++x) {
// get current index in 2D-matrix
int index = y * width + x;
pixel = pixels[index];
if(pickedPanelsList.contains(pixel)){
pixels[index] = Color.argb(ABad, RBad, GBad, BBad);
} else if (Color.alpha(pixel) > 0){
pixels[index] = Color.argb(AGood, RGood, GGood, BGood);
}
}
}
bmOut.setPixels(pixels, 0, width, 0, 0, width, height);
return bmOut;
}
Here, the picked panel set is all the colours that should be coloured red (or chosen) and the bitmap is the mask (if I remember correctly, I did this a while ago). I've also found that doing a slight blur on the result makes the image look nicer - since it will obviously be less jagged.
I've been working on an extension of a current application to stream webcam data to an Android device. I can obtain the raw image data, in the form of a RGB byte array. The color space is sRGB. I need to send that array over the network to an Android client, who constructs it into a Bitmap image to display on the screen. My problem is that the color data is skewed. The arrays have the same hashcode before and after being sent, so I'm positive this isn't a data loss problem. I've attached a sample image of how the color looks, you can see that skin tones and darker colors reconstruct okay, but lighter colors end up with a lot of yellow/red artifacts.
Server (Windows 10) code :
while(socket.isConnected()) {
byte[] bufferArray = new byte[width * height * 3];
ByteBuffer buff = cam.getImageBytes();
for(int i = 0; i < bufferArray.length; i++) {
bufferArray[i] = buff.get();
}
out.write(bufferArray);
out.flush();
}
Client (Android) code :
while(socket.isConnected()) {
int[] colors = new int[width * height];
byte[] pixels = new byte[(width * height) * 3];
int bytesRead = 0;
for(int i = 0; i < (width * height * 3); i++) {
int temp = in.read();
if(temp == -1) {
Log.d("WARNING", "Problem reading");
break;
}
else {
pixels[i] = (byte) temp;
bytesRead++;
}
}
int colorIndex = 0;
for(int i = 0; i < pixels.length; i += 3 ) {
int r = pixels[i];
int g = pixels[i + 1];
int b = pixels[i + 2];
colors[colorIndex] = Color.rgb( r, g, b);
colorIndex++;
}
Bitmap image = Bitmap.createBitmap(colors, width, height, Bitmap.Config.ARGB_8888);
publishProgress(image);
}
The cam.getImageBytes() is from an external library, but I have tested it and it works properly. Reconstructing the RAW data into a BufferedImage works perfectly, using the code :
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
image.getRaster().setPixels(0,0,width,height, pixels);
But, of course, BufferedImages are not supported on Android.
I'm about to tear my hair out with this one, I've tried everything I can think of, so any and all insight would be extremely helpful!
I'm trying to create a function that gets a bitmap and destiny color and returns the colored bitmap (without using paint). I found few ways of doing it but nothing works like I want it to.
The closest solution I was able to find is:
public static Bitmap changeImageColor(Bitmap srcBmp, int dstColor) {
int width = srcBmp.getWidth();
int height = srcBmp.getHeight();
float srcHSV[] = new float[3];
float dstHSV[] = new float[3];
Bitmap dstBitmap = Bitmap.createBitmap(width, height, Config.RGB_565);
for (int row = 0; row < height; row++) {
for (int col = 0; col < width; col++) {
Color.colorToHSV(srcBmp.getPixel(col, row), srcHSV);
Color.colorToHSV(dstColor, dstHSV);
// If it area to be painted set only value of original image
dstHSV[2] = srcHSV[2]; // value
int color2=Color.HSVToColor(dstHSV);;
dstBitmap.setPixel(col, row, Color.HSVToColor(dstHSV));
}
}
return dstBitmap;
}
but It doesn't work very well on transparent images as can be seen here (before and after):
Anyone has any other solutions (again without using paint at all)?
You just need to extract alpha and re-apply it after transformation. And use ARGB_8888;
Edited your code to include alpha:
public Bitmap colorize(Bitmap srcBmp, int dstColor) {
int width = srcBmp.getWidth();
int height = srcBmp.getHeight();
float srcHSV[] = new float[3];
float dstHSV[] = new float[3];
Bitmap dstBitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);
for (int row = 0; row < height; row++) {
for (int col = 0; col < width; col++) {
int pixel = srcBmp.getPixel(col, row);
int alpha = Color.alpha(pixel);
Color.colorToHSV(pixel, srcHSV);
Color.colorToHSV(dstColor, dstHSV);
// If it area to be painted set only value of original image
dstHSV[2] = srcHSV[2]; // value
dstBitmap.setPixel(col, row, Color.HSVToColor(alpha, dstHSV));
}
}
return dstBitmap;
}
here is a sample code for change the color for a bitmap:
private BitmapDrawable getColoredBitmap(int color, Context context,
int drawableId) {
Bitmap source = BitmapFactory.decodeResource(context.getResources(),
drawableId);
final Bitmap bitmap = Bitmap.createBitmap(source.getWidth(),
source.getHeight(), Bitmap.Config.ARGB_8888);
for (int i = 0; i < source.getWidth(); i++) {
for (int j = 0; j < source.getHeight(); j++) {
int pixel = source.getPixel(i, j);
// if (pixel == Color.TRANSPARENT) {
//
// } else
if (pixel == Color.WHITE) {
pixel = Color.argb(Color.alpha(pixel),
Color.red(Color.WHITE), Color.green(Color.WHITE),
Color.blue(Color.WHITE));
} else {
pixel = Color.argb(Color.alpha(pixel), Color.red(color),
Color.green(color), Color.blue(color));
}
bitmap.setPixel(i, j, pixel);
}
}
return new BitmapDrawable(context.getResources(), bitmap);
}
You do this:
int alpha=srcBmp.getPixel(col, row);
dstBitmap.setPixel(col, row, Color.HSVToColor(dstHSV));
in which you calculate an alpha (probably incorrectly from the looks of that code) and then don't use it. You are probably going to have to create a Color with HSVToColor, then set the alpha of that color, then use it in setPixel. And you are probably going to have to get the alpha in a similar way because I find it hard to believe a getPixel function only returns the alpha :p
Hi everyone i have problems in converting GrayScale bmp images into integer 2D-array (with values 0-255) in Java.
I have a pmb image that could be seen as an integer(0-255) 2D-array and i want to see that 2D-array in a Java data structure
i tried this way:
Image image = ImageIO.read(new File("my_img.bmp"));
BufferedImage img = new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_BYTE_GRAY);
Graphics g = img.createGraphics();
g.drawImage(image, 0, 0, null);
g.dispose();
Then with my BufferedImage i create int[][] this way:
int w = img.getWidth();
int h = img.getHeight();
int[][] array = new int[w][h];
for (int j = 0; j < w; j++) {
for (int k = 0; k < h; k++) {
array[j][k] = img.getRGB(j, k);
}
}
But now all the 2D-array is full of number like "-9211021" or similar.
i think that the problem is in getRGB(j,k) but i don't know if it's possible to solve it.
edit:
i know RGB is not grayscale, so how can i get the grayscale value of a single pixel from a grayscale BufferedImage?
In a grayscale image, BufferedImage.getPixel(x,y) wont give values within the [0-255] range. Instead, it returns the corresponding value of a gray level(intensity) in the RGB colorspace. That's why you are getting values like "-9211021".
The following snippet should solve your problem :
Raster raster = image.getData();
for (int j = 0; j < w; j++) {
for (int k = 0; k < h; k++) {
array[j][k] = raster.getSample(j, k, 0);
}
}
where image is the created BufferedImage. The 0 in the getSample indicates that we are accessing the first byte/band(setting it to a greater value will throw a ArrayOutOfBoundException in grayscale images).
You can use Catalano Framework. Contains several filters for image processing.
http://code.google.com/p/catalano-framework/
Detail: That's it faster than using WritableRaster.
FastBitmap fb = new FastBitmap(bufferedImage);
int[][] image = new int[fb.getHeight()][fb.getWidth];
fb.toArrayGray(image);
//Do manipulations with image
//...
//Place the image into fastBitmap
fb.arrayToImage(image);
//Retrieve in bufferedImage if you desire.
bufferedImage = fb.toBufferedImage();
I'm creating a simple program which accepts a gray scale image as an input and what I simply want to do is retrieve the color information of each pixel, store it in an array of objects I call PixelClass. The ultimate goal is simply to repaint the image to a new BufferedImage using the said acquired color information.
Code used to create the pixel array from a given image.
public static PixelClass[][] getPixelArray(BufferedImage bi){
int height = bi.getHeight();
int width = bi.getWidth();
PixelClass[][] pixelArray = new PixelClass[height][width];
for(int i = 0 ; i < height ; i++){
for(int j = 0 ; j < width ; j++){
pixelArray [i] [j] = new PixelClass(bi.getRGB(j, i));
}
}
return pixelArray;
}
Code used to attempt to repaint the said image, using the array of PixelClass objects
public void paintToPanel(PixelClass [][] pc, int height, int width){
BufferedImage nbi = new BufferedImage(width, height,BufferedImage.TYPE_INT_RGB);
for ( int i = 0 ; i < height ; i++){
for ( int j = 0 ; j < width ; j++){
nbi.setRGB(j, i, pc[i][j].getRGBValue());
}
}
JLabel containerLabel = new JLabel(new ImageIcon(nbi));
containerLabel.setBounds(10,10,nbi.getHeight(), nbi.getWidth());
this.add(containerLabel);
}
Links to original images
http://sphotos.ak.fbcdn.net/hphotos-ak-snc4/hs1364.snc4/163667_172099429501181_100001033756527_413302_3062182_n.jpg
As you can see there is significant degradation on the quality of the image. The resulting image appear to be faded.
I would suggest you use the MemoryImageSource class. Something like :
byte[] pixels = // your pixels
ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY);
int bits[] = new int[] {8};
ColorModel cm = new ComponentColorModel(cs, bits, false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
MemoryImageSource mis = new MemoryImageSource(width, height, cm, pixels, 0, width);
Image im = Toolkit.getDefaultToolkit().createImage(mis);