I want to shade a bitmap from one color to the other gradually (So as if it's going to glow from not so red to gradually getting redder.
I'm doing this per pixel but it's causing the app to jump, can someone show me a more efficient method?
private void adjustCountryBitmapColor()
{
//TODO Possible memory leak in this method.
mAllPixels = new int [ mCountryBitmap.getHeight()* mCountryBitmap.getWidth()];
mCountryBitmap.getPixels(mAllPixels, 0, mCountryBitmap.getWidth(), 0, 0, mCountryBitmap.getWidth(),mCountryBitmap.getHeight());
/*
int alpha=argb>>24;
int red=(argb & 0x00FF0000)>>16;
int green=(argb & 0x0000FF00)>>8;
int blue=(argb & 0x000000FF);
*/
for(int i =0; i< mCountryBitmap.getHeight()*mCountryBitmap.getWidth(); i++)
{
if(mAllPixels[i]>>24 == -1)
{
/*AllPixels[i] == Color.BLACK)
{
mAllPixels[i] = Color.RED;
}
*/
mAllPixels[i] = Color.RED;
}
}
System.out.println(mDeltaOffSet);
//int alpha = mAllPixels[0]>>24;
//System.out.println(alpha);
mCountryBitmap.setPixels(mAllPixels, 0, mCountryBitmap.getWidth(), 0, 0, mCountryBitmap.getWidth(), mCountryBitmap.getHeight());
}
Don't create an intermediate bitmap, that's going to take too long; there's Canvas#drawBitmap(int[],....) for exactly that reason. Also, have look whether Paint#setColorFilter() with a ColorMatrixFilter and a ColorMatrix can cover your color transforms.
I had found a good Image Processing library which is using GPU. Its is so fast that you can do live camera as well immediate image processing.
Library is provided by javierpuntonet / android-gpuimage. Just take a look at it and I am sure, you will get benefit of using it.
Related
I would like to build a kind of image morphing tool in Processing. Similar to what you can see in this link:
https://giphy.com/gifs/painting-morph-oil-c8ygOpL64UDuw
My first step to achieve this was to build a two-dimensional grid of pixels. The pixels are filled with colour. The fill colour is created by reading colour from an image (PImage img1;) with the get(); function. This is how I recreated an image with my pixels. In the second step, I thought I would use the lerp(); function to give the respective pixels the colour of a second image (PImage img2;) - I thought this would create the desired morph effect. But I was wrong! The whole thing works - but the effect is only that a fade-in takes place between the two images. And no morphing. What exactly happens to pixels while this morph effect? How could I recreate it in Processing?
float pixel;
float pixelsize;
PImage img1;
PImage img2;
float counter;
void setup() {
size(1080, 1080);
pixel = 100;
pixelsize = width/pixel;
noStroke();
img1 = loadImage("0.jpg");
img2 = loadImage("1.jpg");
counter = 0;
}
void draw() {
background(255);
for (int y = 0; y < pixel; y++) {
for (int x = 0; x < pixel; x++) {
color c1 = img1.get(int(pixelsize*x), int(pixelsize*y));
color c2 = img2.get(int(pixelsize*x), int(pixelsize*y));
color from = c1;
color to = c2;
color interA = lerpColor(from, to, counter);
pushMatrix();
translate(pixelsize*x, pixelsize*y);
fill(interA);
rect(0, 0, pixelsize, pixelsize);
popMatrix();
}
}
counter= counter + 0.01;
}
Indeed it is not a straight forward task.
You're approach is not a bad start: it would result in a nice crossfade between the two images.
Bare in mind get() can be costly on the CPU.
You can however use the pixels[]:
PImage img1;
PImage img2;
// transition image
PImage imgT;
void setup() {
size(1080, 1080);
img1 = loadImage("0.jpg");
img2 = loadImage("1.jpg");
// copy the 1st image (copies width/height as well)
imgT = img1.get();
}
void draw() {
background(255);
// map transition amount to mouse X position
float t = map(mouseX, 0, width, 0.0, 1.0);
// make all pixels readable
imgT.loadPixels();
// lerp each pixel
for(int i = 0 ; i < imgT.pixels.length; i++){
imgT.pixels[i] = lerpColor(img1.pixels[i], img2.pixels[i], t);
}
// update all pixels in one go
imgT.updatePixels();
// display result
image(imgT, 0, 0);
}
Implementing a full morph image is non-trivial.
I can recomend two options to make use of existing algorithms, however these options are also not beginner friendly:
ImageMagick implements shepards distortion and there is a java library that interfaces with imagemagick: im4java. Note that you'd need to download the precompiled java library and drop the .jar file on top of your sketch and processing the output might take time: probably not feasible for realtime (however it should be possible to save individual frames to disk and assemble them as a gif/movie/etc.)
Using OpenCV: there's an OpenCV Face Morph tutorial with source code in c++ or Python and there is a Processing OpenCV library. It would be a matter of porting the c++/Python OpenCV calls to the Java OpenCV API.
I have an image with a green background.
I used this function to remove the background.
public void removeBackground(PImage img, color c, float thres) {
colorMode(HSB);
for(int i = 0; i < img.width; i++){
for(int j = 0; j < img.height; j++){
color cp = img.get(i, j);
//threshold accounts for compression
if(abs(hue(cp) - hue(c)) < thres){
img.set(i, j, color(0,0,0,0));
}
}
}
}
Using these parameters, I attempted to remove the background.
PImage FBSprite;
public void settings() {
size(500, 500);
}
void setup(){
FBSprite = loadImage("FlappyBirdSprite.jpg");
FBSprite.resize(50, 0);
removeBackground(FBSprite, FBSprite.get(0,0), 0.5);
image(FBSprite, 0, 0);
}
void draw(){
background(200);
image(FBSprite, 0, 0);
}
The background turns to black instead of transparent.
ARGB result:
HSB result with 1 alpha:
You are going to love this: change this line
colorMode(HSB);
for this:
colorMode(ARGB);
And it should do the trick. What just happened? Unless you need to work in HSB at that very specific point, there's no point to it. ARGB is just like RGB but it has an ALPHA setting, or transparency if you prefer. Seems like you already were ready to work in ARGB since you set color(0,0,0,0) like this, so this may be a a copy and paste programming issue. Or maybe you just didn't notice. It happens to me all the time. If that's the first thing, though, try to keep a keen eye for this kind of problem in the future. Most people doesn't talk about other bad design patterns except for spaghetti code which everybody knows, but cut and paste programming is real and it hurts a lot, especially if you work with some in-house platform with inexistant documentation. Not that it happened to me.
Have fun!
Instead of setting the alpha of the pixels being removed to 0, I set the alpha to 1. The alpha is so small that you can't see the border.
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'm currently working on a system which displays video frames (as bitmaps) via OpenGL ES 1.0 on Android. My issue is that I have not been able to get more than about 10 fps.
After doing some testing, I've determined that one of the biggest bottlenecks is the need for the bitmap to have its width and height both be a power of 2. A 640x480 video has to be scaled up to 1024x1024, for example. Without the scaling, I've been able to get about 40-50fps, but the texture just appears white, which does me no good.
I know that OpenGL ES 2.0 supports using non-power of two textures, but I have no experience with shaders / anything else new in 2.0
Is there any way I can get around this issue? How do other video plays get such good performance in comparison to what I have? I have included some code for reference.
private Bitmap makePowerOfTwo(Bitmap bitmap)
{
// If one of the bitmap's resolutions is not a power of two
if(!isPowerOfTwo(bitmap.getWidth()) || !isPowerOfTwo(bitmap.getHeight()))
{
int newWidth = nextPowerOfTwo(bitmap.getWidth());
int newHeight = nextPowerOfTwo(bitmap.getHeight());
// Generate a new bitmap which has the needed padding
return Bitmap.createScaledBitmap(bitmap, newWidth, newHeight, true);
}
else
{
return bitmap;
}
}
private static boolean isPowerOfTwo(int num)
{
// Check if a bitwise and of the number and itself minus one is zero
return (num & (num - 1)) == 0;
}
private static int nextPowerOfTwo(int num)
{
if(num <= 0)
{
return 0;
}
int nextPowerOfTwo = 1;
while(nextPowerOfTwo < num)
{
nextPowerOfTwo <<= 1; // Bitwise shift left one bit
}
return nextPowerOfTwo;
}
Just because a texture has to be a power of two, doesn't mean that your data has to be a power of two.
You're free to create a 1024x1024 (or 1024x512) texture during initialization with glTexImage, fill in the lower 640x480 with your bitmap data with glTexSubImage, and then display the lower 640x480 of the texture with some intelligent texcoords (0,0) to (640/1024, 480/1024). The remainder of the texture will just contain empty space that's never seen.
I have the following problem. I have a charting program, and it's design is black, but the charts (that I get from the server as images) are light (it actually uses only 5 colors: red, green, white, black and gray).
To fit with the design inversion does a good job, the only problem is that red and green are inverted also (green -> pink, red -> green).
Is there a way to invert everything except those 2 colors, or a way to repaint those colors after inversion?
And how costly are those operations (since I get the chart updates pretty often)?
Thanks in advance :)
UPDATE
I tried replacing colors with setPixel method in a loop
for(int x = 0 ;x < chart.getWidth();x++) {
for(int y = 0;y < chart.getHeight();y++) {
final int replacement = getColorReplacement(chart.getPixel(x, y));
if(replacement != 0) {
chart.setPixel(x, y, replacement);
}
}
}
Unfortunetely, the method takes too long (~650ms), is there a faster way to do it, and will setPixels() method work faster?
Manipulating a bitmap is much faster if you copy the image data into an int array by calling getPixels only once, and don't call any function inside the loop. Just manipulate the array, then call setPixels at the end.
Something like that:
int length = bitmap.getWidth()*bitmap.getHeight();
int[] array = new int[length];
bitmap.getPixels(array,0,bitmap.getWidth(),0,0,bitmap.getWidth(),bitmap.getHeight());
for (int i=0;i<length;i++){
// If the bitmap is in ARGB_8888 format
if (array[i] == 0xff000000){
array[i] = 0xffffffff;
} else if ...
}
}
bitmap.setPixels(array,0,bitmap.getWidth(),0,0,bitmap.getWidth(),bitmap.getHeight());
If you have it available as BufferedImage, you can access its raster and edit it as you please.
WritableRaster raster = my_image.getRaster();
// Edit all the pixels you wanna change in the raster (green -> red, pink -> green)
// for (x,y) in ...
// raster.setPixel(x, y, ...)
my_image.setData(raster);
OK seen that you're really only using 5 colors it's quite easy.
Regarding performances, I don't know about Android but I can tell you that in Java using setRGB is amazingly slower than getting back the data buffer and writing directly in the int[].
When I write "amazingly slower", to give you an idea, on OS X 10.4 the following code:
for ( int x = 0; x < width; x++ ) {
for ( int y = 0; y < height; y++ ) {
img.setRGB(x,y,0xFFFFFFFF);
}
}
can be 100 times (!) slower than:
for ( int x = 0; x < width; x++ ) {
for ( int y = 0; y < height; y++ ) {
array[y*width+x] = 0xFFFFFFFF;
}
}
You read correctly: one hundred time. Measured on a Core 2 Duo / Mac Mini / OS X 10.4.
(of course you need to first get access to the underlying int[] array but hopefully this shouldn't be difficult)
I cannot stress enough that the problem ain't the two for loops: in both cases it's the same unoptimized for loops. So it's really setRGB that is the issue here.
I don't know it works on Android, but you probably should get rid of setRGB if you want something that performs well.
A quick way would be to use AvoidXfermode to repaint just those colors you want changed - you could then switch between any colors you want. You just need to do something like this:
// will change red to green
Paint change1 = new Paint();
change1.setColor(Color.GREEN);
change1.setXfermode(new AvoidXfermode(Color.RED, 245, AvoidXfermode.Mode.TARGET));
Canvas c = new Canvas();
c.setBitmap(chart);
c.drawRect(0, 0, width, height, change1);
// rinse, repeat for other colors
You may need to play with the tolerance for the AvoidXfermode, but that should do what you want a lot faster than a per-pixel calculation. Also, make sure your chart image is in ARGB8888 mode. By default, Android tends to work with images in RGB565 mode, which tends to mess up color calculations like you want to use - to be sure, you can make sure your image is both in ARGB8888 mode and mutable by calling Bitmap chart = chartFromServer.copy(Config.ARGB_8888, true); before you setup the Xfermode.
Clarification: to change other colors, you wouldn't have to re-load the images all over again, you would just have to create other Paints with the appropriate colors you want changed like so:
// changes green to red
Paint change1 = new Paint();
change1.setColor(Color.GREEN);
change1.setXfermode(new AvoidXfermode(Color.RED, 245, AvoidXfermode.Mode.TARGET));
// changes white to blue
Paint change2 = new Paint();
change2.setColor(Color.BLUE);
change2.setXfermode(new AvoidXfermode(Color.WHITE, 245, AvoidXfermode.Mode.TARGET));
// ... other Paints with other changes you want to apply to this image
Canvas c = new Canvas();
c.setBitmap(chart);
c.drawRect(0, 0, width, height, change1);
c.drawRect(0, 0, width, height, change2);
//...
c.drawRect(0, 0, width, height, changeN);