for my final year project I am developing an android app that can capture the image of a leaf and identify what type of tree it came from. I have a nearly completed PC version (developed in java) and i am starting the process of porting it to android. Although BufferedImage and Raster make up a key part of my program, this is a problem because java.awt is missing in android, so this means i have to alter the library.
I am using a library that was developed by my lecturer, the method below converts a BufferedImage to an IntImage(a type that is used throughout the package) using Raster.
I'm basically asking are there any android alternatives to java.awt that i can use?
Here's the code:
public static int[][] readAsInts(String fileName) throws IOException {
int[][] pixels;
System.out.println("File: " + fileName);
String [] types = ImageIO.getReaderFileSuffixes();
for (int l = 0; l < types.length; l++) {
System.out.println("Type " + l + ": " + types[l]);
}
File f = new File(fileName);
BufferedImage bi;
bi = ImageIO.read(f);
int cols = bi.getWidth();
int rows = bi.getHeight();
System.err.println("Number of bands: " + bi.getRaster().getNumBands());
Raster rast = bi.getRaster();
pixels = new int[rows][cols];
for (int r = 0; r < rows; r++) {
rast.getSamples(0, r, cols, 1, 0, pixels[r]);
}
return pixels;
} // readAsInts
Thanks guys!
EDIT: For anyone who doesn't know the raster stores the pixel values for the BufferedImage, along with the number of bands (red, green, blue, alpha), so this algorithm takes the pixel values ad stores them in a 2d array (pixels).
Sounds like you just want to work with bitmaps and be able to manipulate the pixels themselves in an array. The Bitmap class comes to mind along with its getPixels method. Remember though that you have much more limited memory on a mobile device. It's easy to run into out of memory problems when working with large bitmaps.
Another route would be to use the NDK. I don't have much experience there, but AndroidBitmap_lockPixels and AndroidBitmap_unlockPixels are probably a good place to start.
Lastly, yet another option that should perform pretty well is to use RenderScript.
If all you're looking to do is load an image into an int array though, Bitmap.getPixels should be quite sufficient.
You can convert a BufferedImage to a PNG or JPEG, then send it via HTTP to Android which can then convert the PNG or JPEG back to a Bitmap and use it.
When Android needs to send any image, send it as PNG or JPEG via network, and then convert the PNG to BufferedImage and use it in your program.
Related
I am working on a module in which I have to make background of bitmap image transparent. Actually, I am making an app like "Stick it" through which we can make sticker out of any image. I don't know from where to begin.
Can someone give me a link or a hint for it?
Original Image-
After making background transparent-
This is what I want.
I can only provide some hints on how to approach your problem. You need to do a Image Segmenation. This can be achived via the k-means algotithm or similar clustering algorithms. See this for algorithms on image segmantation via clustering and this for a Java Code example. The computation of the clustering can be very time consumeing on a mobile device. Once you have the clustering you can use this approach to distinguish between the background and the foreground. In general all you picture should have a bachground color which differs strongly from the foreground otherwise it is not possible for the clustering to distunguish between them. It can also happen that a pixel inside of you foreground is assigned to the cluster of the background beacuase it has a similar color like your background. To prevent this from happening you could use this approach or a region grwoth algorithm. Afterward you can let you user select the clusters via touch and remove them. I also had the same problems with my Android App. This will give you a good start and once you have implemented the custering you just need to tewak the k parameter of the clustering to get good results.
Seems like a daunting task. If you are talking about image processing if I may understand then you can try https://developers.google.com/appengine/docs/java/images/
Also if you want to mask the entire background ( I have not tried Stick it) the application needs to understand the background image map. Please provide some examples so that I can come up with more definitive answers
One possibility would be to utilize the floodfill operation in the openCV library. There are lots of examples and tutorials on how to do similar stuff to what you want and OpenCV has been ported to Android. The relevant terms to Google are of course "openCV" and "floodfill".
For this kind of task(and app) you'll have to use openGL. Usually when working on openGL you based your fragment shader on modules you build in Matlab. Once you have the fragment shader it's quite easy to apply it on image. check this guide how to do it.
Here's a link to remove background from image in MatLab
I'm not fully familiar with matlab and if it can generate GLSL code by itself(the fragment shader). But even if it doesn't - you might want to learn GLSL yourself because frankly - you are trying to build a graphics app and Android SDK is somehow short when using it for images manipulation, and most important is that without a strong hardware-acceleration engine behind it - I cannot see it works smooth enough.
Once you'll have the figure image - you can apply it on transparent background easily like this:
Canvas canvas = new Canvas(canvasBitmap);
canvas.drawColor(Color.TRANSPARENT);
BitmapDrawable bd = (BitmapDrawable) getResources().getDrawable(R.drawable.loading);
Bitmap yourBitmap = bd.getBitmap();
Paint paint = new Paint();
canvas.drawBitmap(yourBitmap, 0, 0, paint);
Bitmap newBitmap = Bitmap.createBitmap(image.getWidth(), image.getHeight(),image.getConfig());
Canvas canvas = new Canvas(newBitmap);
canvas.drawColor(Color.TRANSPARENT);
canvas.drawBitmap(image, 0, 0, null);
OR
See this
hope this wll helps you
if you are working in Android you might need a Buffer to get the pixels from the image - it's a intBuffer and it reduces the memory usage enormously... to get data from and stor data into the Buffer you have three methods (you can skip that part if you don't have 'large' images):
private IntBuffer buffer;
public void copyImageIntoBuffer(File imgSource) {
final Bitmap temp = BitmapFactory.decodeFile(imgSource
.getAbsolutePath());
buffer.rewind();
temp.copyPixelsToBuffer(buffer);
}
protected void copyBufferIntoImage(File tempFile) throws IOException {
buffer.rewind();
Bitmap temp = Bitmap.createBitmap(imgWidth, imgHeight,
Config.ARGB_8888);
temp.copyPixelsFromBuffer(buffer);
FileOutputStream out = new FileOutputStream(tempFile);
temp.compress(Bitmap.CompressFormat.JPEG, 90, out);
out.flush();
out.close();
}
public void mapBuffer(final File tempFile, long size) throws IOException {
RandomAccessFile aFile = new RandomAccessFile(tempFile, "rw");
aFile.setLength(4 * size); // 4 byte pro int
FileChannel fc = aFile.getChannel();
buffer = fc.map(FileChannel.MapMode.READ_WRITE, 0, fc.size())
.asIntBuffer();
}
now you can use the Buffer to get the pixels and modify them as desired... (i've copyied a code snipped that used a Progress bar on my UI and therefore needed a Handler/ProgressBar... when i did this i was working on bigger images and implemented a imageFilter (Gauss-Filter,Grey-Filter, etc.... just delete what is not needed)
public void run(final ProgressBar bar, IntBuffer buffer, Handler mHandler, int imgWidth, int imgHeight, int transparentColor ) {
for (int dy = 0; dy < imgHeight; dy ++){
final int progress = (dy*100)/imgHeight;
for (int dx = 0; dx < imgWidth; dx ++ ){
int px = buffer.get();
//int a = (0xFF000000 & px);
//int r = (0x00FF0000 & px) >> 16;
//int g = (0x0000FF00 & px) >> 8;
//int b = (0x000000FF & px);
//this makes the color transparent
if (px == transparentColor) {
px = px | 0xFF000000;
}
//r = mid << 16;
//g = mid << 8;
//b = mid;
//int col = a | r | g | b;
int pos = buffer.position();
buffer.put(pos-1, px);
}
// Update the progress bar
mHandler.post(new Runnable() {
public void run() {
bar.setProgress(progress);
}
});
}
}
if you really have small images, you can get the pixels directly during onCreate() or even better create a Buffer (maybe a HashMap or a List) before you start the Activity...
I plan to have an animated character (the character's image changing multiple times to make it appear to be moving), and I would like to know the best way to do it. I am currently planning to do something like this:
String fileLocation = "./images/picture";
BufferedImage img;
int numImages = 10;
for(int i = 0; i < numImages; i++){
img = ImageIO.read(new File(fileLocation + i + ".png"));
Thread.sleep(100);
g.drawImage(img, 0, 0, null);
}
This is an incredibly simplified version, missing a few things, but I'm sure you get what I mean. Are there any problems doing it this way? (Note: the for loop would repeat again straight after finishing, and there would be files called "picture0.png", "picture1.png", etc. in the "images" folder)
If the images are not huge and don't require a lot of memory for storing them, I would rather read the images first and cache them. When they need to be displayed, I would read them from memory rather than from disk.
I am using Xuggle to play interlaced video from ip-camera and really need in deinterlace option, which exists in FFMpeg (Xuggle is a java wrapper over FFMpeg library).
Unfortunately, deinterlace option ("-vf yadif", if i'm not mistake) is not exposed by Xuggle. So, i'm interested in either pure java solution of Java BufferedImage deinterlacing or some way to make Xuggle do that.
Now i simply duplicate odd lines and discard even. It is quick but quality of course is not very well.
// Interlaced image
BufferedImage img = (BufferedImage) event.getImage();
//duplicate odd lines
WritableRaster raster = img.getRaster();
for (int i = 0; i < raster.getHeight(); i += 2) {
int[] arr2 = null;
raster.setPixels(0, i + 1, raster.getWidth(), 1,
raster.getPixels(0, i, raster.getWidth(), 1,arr2));
}
//now img is deinterlaced
Could somebody help me in this regard?
I used FFMPEG's yadif filter through JNI. Java realisations were very slow.
I have a method converting BufferedImages who's type is TYPE_CUSTOM to TYPE_INT_RGB. I am using the following code, however I would really like to find a faster way of doing this.
BufferedImage newImg = new BufferedImage(
src.getWidth(),
src.getHeight(),
BufferedImage.TYPE_INT_RGB);
ColorConvertOp op = new ColorConvertOp(null);
op.filter(src, newImg);
It works fine, however it's quite slow and I am wondering if there is a faster way to do this conversion.
ColorModel Before Conversion:
ColorModel: #pixelBits = 24 numComponents = 3 color space = java.awt.color.ICC_ColorSpace#1c92586f transparency = 1 has alpha = false isAlphaPre = false
ColorModel After Conversion:
DirectColorModel: rmask=ff0000 gmask=ff00 bmask=ff amask=0
Thanks!
Update:
Turns out working with the raw pixel data was the best way. Since the TYPE_CUSTOM was actually RGB converting it manually is simple and is about 95% faster than ColorConvertOp.
public static BufferedImage makeCompatible(BufferedImage img) throws IOException {
// Allocate the new image
BufferedImage dstImage = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_RGB);
// Check if the ColorSpace is RGB and the TransferType is BYTE.
// Otherwise this fast method does not work as expected
ColorModel cm = img.getColorModel();
if ( cm.getColorSpace().getType() == ColorSpace.TYPE_RGB && img.getRaster().getTransferType() == DataBuffer.TYPE_BYTE ) {
//Allocate arrays
int len = img.getWidth()*img.getHeight();
byte[] src = new byte[len*3];
int[] dst = new int[len];
// Read the src image data into the array
img.getRaster().getDataElements(0, 0, img.getWidth(), img.getHeight(), src);
// Convert to INT_RGB
int j = 0;
for ( int i=0; i<len; i++ ) {
dst[i] = (((int)src[j++] & 0xFF) << 16) |
(((int)src[j++] & 0xFF) << 8) |
(((int)src[j++] & 0xFF));
}
// Set the dst image data
dstImage.getRaster().setDataElements(0, 0, img.getWidth(), img.getHeight(), dst);
return dstImage;
}
ColorConvertOp op = new ColorConvertOp(null);
op.filter(img, dstImage);
return dstImage;
}
BufferedImages are painfully slow. I got a solution but I'm not sure you will like it. The fastest way to process and convert buffered images is to extract the raw data array from inside the BufferedImage. You do that by calling buffImg.getRaster() and converting it into the specific raster. Then call raster.getDataStorage(). Once you have access to the raw data it is possible to write fast image processing code without all the abstraction in BufferedImages slowing it down. This technique also requires an in depth understanding of image formats and some reverse engineering on your part. This is the only way I have been able to get image processing code to run fast enough for my applications.
Example:
ByteInterleavedRaster srcRaster = (ByteInterleavedRaster)src.getRaster();
byte srcData[] = srcRaster.getDataStorage();
IntegerInterleavedRaster dstRaster = (IntegerInterleavedRaster)dst.getRaster();
int dstData[] = dstRaster.getDataStorage();
dstData[0] = srcData[0] << 16 | srcData[1] << 8 | srcData[2];
or something like that. Expect compiler errors warning you not to access low level rasters like that. The only place I have had issues with this technique is inside of applets where an access violation will occur.
I've found rendering using Graphics.drawImage() instead of ColorConvertOp 50 times faster. I can only assume that drawImage() is GPU accelerated.
i.e this is really slow, like 50ms a go for 100x200 rectangles
public void BufferdImage convert(BufferedImage input) {
BufferedImage output= new BufferedImage(input.getWidht(), input.getHeight(), BufferedImage.TYPE_BYTE_BINARY, CUSTOM_PALETTE);
ColorConvertOp op = new ColorConvertOp(input.getColorModel().getColorSpace(),
output.getColorModel().getColorSpace());
op.filter(input, output);
return output;
}
i.e however this registers < 1ms for same inputs
public void BufferdImage convert(BufferedImage input) {
BufferedImage output= new BufferedImage(input.getWidht(), input.getHeight(), BufferedImage.TYPE_BYTE_BINARY, CUSTOM_PALETTE);
Graphics graphics = output.getGraphics();
graphics.drawImage(input, 0, 0, null);
graphics.dispose();
return output;
}
Have you tried supplying any RenderingHints? No guarantees, but using
ColorConvertOp op = new ColorConvertOp(new RenderingHints(
RenderingHints.KEY_COLOR_RENDERING,
RenderingHints.VALUE_COLOR_RENDER_SPEED));
rather than the null in your code snippet might speed it up somewhat.
I suspect the problem might be that ColorConvertOp() works pixel-by-pixel (guaranteed to be "slow").
Q: Is it possible for you to use gc.createCompatibleImage()?
Q: Is your original bitmap true color, or does it use a colormap?
Q: Failing all else, would you be agreeable to writing a JNI interface? Either to your own, custom C code, or to an external library such as ImageMagick?
If you have JAI installed then you might try uninstalling it, if you can, or otherwise look for some way to disable codecLib when loading JPEG. In a past life I had similar issues (http://www.java.net/node/660804) and ColorConvertOp was the fastest at the time.
As I recall the fundamental problem is that Java2D is not at all optimized for TYPE_CUSTOM images in general. When you install JAI it comes with codecLib which has a decoder that returns TYPE_CUSTOM and gets used instead of the default. The JAI list may be able to provide more help, it's been several years.
maybe try this:
Bitmap source = Bitmap.create(width, height, RGB_565);//don't remember exactly...
Canvas c = new Canvas(source);
// then
c.draw(bitmap, 0, 0);
Then the source bitmap will be modified.
Later you can do:
onDraw(Canvas canvas){
canvas.draw(source, rectSrs,rectDestination, op);
}
if you can manage always reuse the bitmap so you be able to get better performance. As well you can use other canvas functions to draw your bitmap
I am using Java with swing in FSE mode. I want to load a completely black-and-white image into binary format (a 2d array preferably) and use it for mask-based per-pixel collision detection. I don't even know where to start here, I've been researching for the past hour and haven't found anything relevant.
Just read it into a BufferedImage using ImageIO#read() and get the individual pixels by BufferedImage#getRGB(). A value of 0xFFFFFFFF is white and the remnant is color. Assuming that you want to represent white as byte 0 and color (black) as byte 1, here's a kickoff example:
BufferedImage image = ImageIO.read(new File("/some.jpg"));
byte[][] pixels = new byte[image.getWidth()][];
for (int x = 0; x < image.getWidth(); x++) {
pixels[x] = new byte[image.getHeight()];
for (int y = 0; y < image.getHeight(); y++) {
pixels[x][y] = (byte) (image.getRGB(x, y) == 0xFFFFFFFF ? 0 : 1);
}
}
See also:
The Java Tutorials - 2D Graphics - Working with images
If you're reading the image from a URL, it will already be in a binary format. Just download the data and ignore the fact that it's an image. The code which is involved in download it won't care, after all. Assuming you want to write it to a file or something similar, just open the URLConnection and open the FileOutputStream, and repeatedly read from the input stream from the web, writing the data you've read to the output stream.
You can also use ImageIO if you are not downloading it from some resource.