When I am making photo in android I receive a byte array from camera. I would like to convert this array(image) into the 2 colors - white and black. Any ideas? Changing camera mode to mono/negative is not a sollution for me.
Greetings.
EDIT1: Code is in Java
First of all, you need to create bitmap from your array:
BitmapFactory.Options options = new BitmapFactory.Options();
options.inMutable = true;
// data is your byte array
Bitmap bmpOriginal = BitmapFactory.decodeByteArray(data, 0, data.length, options);
Canvas canvas = new Canvas(bmpOriginal);
Bitmap bmpGrayscale = toGrayscale(bmpOriginal);
bmpOriginal.recycle(); // free memory immediately, as your bitmap is not garbage collected by now.
Then, you can pass your bmpOriginal, which is colored image, to converting method
public Bitmap toGrayscale(Bitmap bmpOriginal) {
int width, height;
height = bmpOriginal.getHeight();
width = bmpOriginal.getWidth();
Bitmap bmpGrayscale = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(bmpGrayscale);
Paint paint = new Paint();
ColorMatrix cm = new ColorMatrix();
cm.setSaturation(0);
ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm);
paint.setColorFilter(f);
c.drawBitmap(bmpOriginal, 0, 0, paint);
return bmpGrayscale;
}
Above code will give you grayscale bitmap. It simply applies zero saturation filter to image. As the saturation is the purity of a color, the less purity - the less color difference. After applying above filter the only difference you get is brightness. The brightest is white, the darkest - black. If you want to convert it back to byte array you can try something like this:
Bitmap bmpGrayscale = intent.getExtras().get("data");
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bmpGrayscale.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] byteArray = stream.toByteArray();
bmpGrayscale.recycle(); // free memory immediately, as your bitmap is not garbage collected by now.
Related
I have raw grayscale image pixels represented by short[]. I would like to create BufferedImage from it and save it as PNG.
Since there is no TYPE_SHORT_GRAY defined for BufferedImage I'm creating one myself this way:
short[] myRawImageData;
// Create signed 16 bit data buffer, and compatible sample model
DataBuffer dataBuffer = new DataBufferShort(myRawImageData, w * h);
SampleModel sampleModel = new ComponentSampleModel(DataBuffer.TYPE_SHORT, w, h, 1, w, new int[] {0});
// Create a raster from sample model and data buffer
WritableRaster raster = Raster.createWritableRaster(sampleModel, dataBuffer, null);
// Create a 16 bit signed gray color model
ColorSpace colorSpace = ColorSpace.getInstance(ColorSpace.CS_GRAY);
ColorModel colorModel = new ComponentColorModel(colorSpace, false, false, Transparency.OPAQUE, DataBuffer.TYPE_SHORT);
// Finally create the signed 16 bit image
BufferedImage image = new BufferedImage(colorModel, raster, colorModel.isAlphaPremultiplied(), null);
try (FileOutputStream fos = new FileOutputStream("/tmp/tst.png")) {
ImageIO.write(image, "png", fos);// <--- Here goes the exception
} catch (Exception ex) {
ex.printStackTrace();
}
So far so good but when I'm trying to use ImageIO.write to save it as PNG I'm getting ArrayIndexOutOfBoundsException.
Your code works fine for me, the only way I got your error was when I changed the bandOffsets. Could you give us more of your code?
EDIT
If you have negative data in your dataset, you should probably be using ushort instead of short.
int h = 64, w = 64;
short[] myRawImageData = new short[4096];
for (int i = 0; i < 4096; i++){
//this rolls over into negative numbers
myRawImageData[i] = (short) (i * 14);
}
// Create signed 16 bit data buffer, and compatible sample model
DataBuffer dataBuffer = new DataBufferUShort(myRawImageData, w * h);
SampleModel sampleModel = new ComponentSampleModel(DataBuffer.TYPE_USHORT, w, h, 1, w, new int[] {0});
// Create a raster from sample model and data buffer
WritableRaster raster = Raster.createWritableRaster(sampleModel, dataBuffer, null);
// Create a 16 bit signed gray color model
ColorSpace colorSpace = ColorSpace.getInstance(ColorSpace.CS_GRAY);
ColorModel colorModel = new ComponentColorModel(colorSpace, false, false, Transparency.OPAQUE, DataBuffer.TYPE_USHORT);
// Finally create the signed 16 bit image
BufferedImage image = new BufferedImage(colorModel, raster, colorModel.isAlphaPremultiplied(), null);
try (FileOutputStream fos = new FileOutputStream("/tmp/tst.png")) {
ImageIO.write(image, "png", fos);// <--- Here goes the exception
} catch (Exception ex) {
ex.printStackTrace();
}
This is assuming you expect negative values to be the brighter half of the gamut.
I have an image captured by a camera, in RAW BGRA format (byte array).
How can I save it to disk, as a JPG/PNG file?
I've tried with ImageIO.write from Java API, but I got error IllegalArgumentException (image = null)
CODE:
try
{
InputStream input = new ByteArrayInputStream(img);
BufferedImage bImageFromConvert = ImageIO.read(input);
String path = "D:/image.jpg";
ImageIO.write(bImageFromConvert, "jpg", new File(path));
}
catch(Exception ex)
{
System.out.println(ex.toString());
}
Note that "img" is the RAW byte array, and that is NOT null.
The problem is that ImageIO.read does not support raw RGB (or BGRA in your case) pixels. It expects a file format, like BMP, PNG or JPEG, etc.
In your code above, this causes bImageFromConvert to become null, and this is the reason for the error you see.
If you have a byte array in BGRA format, try this:
// You need to know width/height of the image
int width = ...;
int height = ...;
int samplesPerPixel = 4;
int[] bandOffsets = {2, 1, 0, 3}; // BGRA order
byte[] bgraPixelData = new byte[width * height * samplesPerPixel];
DataBuffer buffer = new DataBufferByte(bgraPixelData, bgraPixelData.length);
WritableRaster raster = Raster.createInterleavedRaster(buffer, width, height, samplesPerPixel * width, samplesPerPixel, bandOffsets, null);
ColorModel colorModel = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), true, false, Transparency.TRANSLUCENT, DataBuffer.TYPE_BYTE);
BufferedImage image = new BufferedImage(colorModel, raster, colorModel.isAlphaPremultiplied(), null);
System.out.println("image: " + image); // Should print: image: BufferedImage#<hash>: type = 0 ...
ImageIO.write(image, "PNG", new File(path));
Note that JPEG is not a good format for storing images with alpha channel. While it is possible, most software will not display it properly. So I suggest using PNG instead.
Alternatively, you could remove the alpha channel, and use JPEG.
With Matlab you can convert all types of images with 2 lines of code:
img=imread('example.CR2');
imwrite(img,'example.JPG');
I need to convert a BufferedImage to a BufferedImage indexed type to extract the indices of the colors data and the 256 color palette.
i think that i am doing right the conversion of a BufferedImage to indexed mode and then extracting the color indices with the next code:
BufferedImage paletteBufferedImage=new BufferedImage(textureInfoSubFile.getWidth(), textureInfoSubFile.getHeight(),BufferedImage.TYPE_BYTE_INDEXED);
paletteBufferedImage.getGraphics().drawImage(originalBufferedImage, 0, 0, null);
// puts the image pixeldata into the ByteBuffer
byte[] pixels = ((DataBufferByte) paletteBufferedImage.getRaster().getDataBuffer()).getData();
My problem now is that i need to know the ARGB values of each color index( the palette) to put them into an array. i have been reading about ColorModel and ColorSpace but i donĀ“t find some methods to do what i need.
I think your code is good (except that you don't "put" any data into anything, you merely reference the data buffer's backing array, meaning changes in pixels will reflect to paletteBufferedImage and vice versa).
To get the ARGB values for the indices in pixels:
IndexColorModel indexedCM = (IndexColorModel) paletteBufferedImage.getColorModel(); // cast is safe for TYPE_BYTE_INDEXED
int[] palette = new int[indexedCM.getMapSize()]; // Allocate array
indexedCM.getRGBs(palette); // Copy palette to array (ARGB values)
For more information, see the IndexColorModel class documentation.
Finally i solve it with this code:
public static BufferedImage rgbaToIndexedBufferedImage(BufferedImage sourceBufferedImage) {
// With this constructor, we create an indexed buffered image with the same dimension and with a default 256 color model
BufferedImage indexedImage = new BufferedImage(sourceBufferedImage.getWidth(), sourceBufferedImage.getHeight(), BufferedImage.TYPE_BYTE_INDEXED);
ColorModel cm = indexedImage.getColorModel();
IndexColorModel icm = (IndexColorModel) cm;
int size = icm.getMapSize();
byte[] reds = new byte[size];
byte[] greens = new byte[size];
byte[] blues = new byte[size];
icm.getReds(reds);
icm.getGreens(greens);
icm.getBlues(blues);
WritableRaster raster = indexedImage.getRaster();
int pixel = raster.getSample(0, 0, 0);
IndexColorModel icm2 = new IndexColorModel(8, size, reds, greens, blues, pixel);
indexedImage = new BufferedImage(icm2, raster, sourceBufferedImage.isAlphaPremultiplied(), null);
indexedImage.getGraphics().drawImage(sourceBufferedImage, 0, 0, null);
return indexedImage;
}
So I make a bitmap from a blob with the next code:
byte[] blob = contact.getMP();
ByteArrayInputStream inputStream = new ByteArrayInputStream(blob);
Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
Bitmap scalen = Bitmap.createScaledBitmap(bitmap, 320, 240, false);
and it gives back the next output, which is good
Then I do the following to make the bitmap into a Mat, but then my colors just change...
//Mat ImageMat = new Mat();
Mat ImageMat = new Mat(320, 240, CvType.CV_32F);
Utils.bitmapToMat(scalen, ImageMat);
I have no idea why, nor another way to make the bitmap into a Mat. What is wrong?
The format of color channels in Android Bitmap are RGB
But in opencv Mat, the channels are BGR by default.
So when you do Utils.bitmapToMat(), [B,G,R] values are stored in [R,G,B] channels. The red and blue channels are interchanged.
One possible solution is to apply cvtcolor on the opencv Mat you got as below:
Imgproc.cvtColor(ImageMat, ImageMat, Imgproc.COLOR_BGR2RGB);
It worked for me.
I have 16-bit per pixel grayscale BufferedImage created from an array of shorts:
private BufferedImage get16bitImage(short[] pixels) {
ColorModel colorModel = new ComponentColorModel(
ColorSpace.getInstance(ColorSpace.CS_GRAY),
new int[]{16},
false,
false,
Transparency.OPAQUE,
DataBuffer.TYPE_USHORT);
DataBufferUShort db = new DataBufferUShort(pixels, pixels.length);
WritableRaster raster = Raster.createInterleavedRaster(
db,
imgD.width,
imgD.height,
imgD.width,
1,
new int[1],
null);
return new BufferedImage(colorModel, raster, false, null);
}
When trying to save it:
ImageIO.write(img, "PNG", new File(resultImgNamePNG)); // works fine
ImageIO.write(img, "BMP", new File(resultImgNameBMP)); // doesn't work, returns false
ImageIO.write(img, "JPEG", new File(resultImgNameJPEG)); // doesnt work, returns false
I tried using JAI:
public void writeImageToJPEG(File out, BufferedImage image, float quality) throws IOException {
JPEGEncodeParam param = new JPEGEncodeParam();
param.setQuality(quality);
ImageEncoder encoder = ImageCodec.createImageEncoder("JPEG", new FileOutputStream(out), param);
encoder.encode(image);
}
encoder.encode(image) throws java.lang.RuntimeException: Only 1, or 3-band byte data may be written.
I think you have to convert it to 8-bit first. If this is used for display purposes, java converts it to 8-bit bit before display anyways.
You can do something that I've seen sometimes actually improve the displayed image which is doing non-linear scaling of the values (using a log scale for example) such detail depends on the image you are generating ofcourse.
More on such effect here: http://www.java.net/external?url=http://www.cs.unm.edu/~brayer/vision/perception.html