I found some code that draws the histogram but I am not sure how to make it show the histogram of _tempBitmaps[0] once the user clicks on a ShowRGB Histogram Button
I want the graphs to be displayed on top of ImageView once the user clicks the button display_RGB and when the user clicks the button again the graphs disappear.
I have also attached a mockup of the layout and the graphs that I wish to achieve.
Mockup:
Below is the sample code I found for histogram and it works but currently some of the variables arent initialised and thats what I need help with :
class DrawOnTop extends View {
Bitmap mBitmap;
Paint mPaintBlack;
Paint mPaintYellow;
Paint mPaintRed;
Paint mPaintGreen;
Paint mPaintBlue;
byte[] mYUVData;
int[] mRGBData;
int mImageWidth, mImageHeight;
int[] mRedHistogram;
int[] mGreenHistogram;
int[] mBlueHistogram;
double[] mBinSquared;
public DrawOnTop(Context context) {
super(context);
mPaintBlack = new Paint();
mPaintBlack.setStyle(Paint.Style.FILL);
mPaintBlack.setColor(Color.BLACK);
mPaintBlack.setTextSize(25);
mPaintYellow = new Paint();
mPaintYellow.setStyle(Paint.Style.FILL);
mPaintYellow.setColor(Color.YELLOW);
mPaintYellow.setTextSize(25);
mPaintRed = new Paint();
mPaintRed.setStyle(Paint.Style.FILL);
mPaintRed.setColor(Color.RED);
mPaintRed.setTextSize(25);
mPaintGreen = new Paint();
mPaintGreen.setStyle(Paint.Style.FILL);
mPaintGreen.setColor(Color.GREEN);
mPaintGreen.setTextSize(25);
mPaintBlue = new Paint();
mPaintBlue.setStyle(Paint.Style.FILL);
mPaintBlue.setColor(Color.BLUE);
mPaintBlue.setTextSize(25);
mBitmap = null;
mYUVData = null;
mRGBData = null;
mRedHistogram = new int[256];
mGreenHistogram = new int[256];
mBlueHistogram = new int[256];
mBinSquared = new double[256];
for (int bin = 0; bin < 256; bin++)
{
mBinSquared[bin] = ((double)bin) * bin;
} // bin
}
#Override
protected void onDraw(Canvas canvas) {
if (mBitmap != null)
{
int canvasWidth = canvas.getWidth();
int canvasHeight = canvas.getHeight();
int newImageWidth = canvasWidth;
int newImageHeight = canvasHeight;
int marginWidth = (canvasWidth - newImageWidth)/2;
// Convert from YUV to RGB
decodeYUV420SP(mRGBData, mYUVData, mImageWidth, mImageHeight);
// Draw bitmap
mBitmap.setPixels(mRGBData, 0, mImageWidth, 0, 0,
mImageWidth, mImageHeight);
Rect src = new Rect(0, 0, mImageWidth, mImageHeight);
Rect dst = new Rect(marginWidth, 0,
canvasWidth-marginWidth, canvasHeight);
canvas.drawBitmap(mBitmap, src, dst, mPaintBlack);
// Draw black borders
canvas.drawRect(0, 0, marginWidth, canvasHeight, mPaintBlack);
canvas.drawRect(canvasWidth - marginWidth, 0,
canvasWidth, canvasHeight, mPaintBlack);
// Calculate histogram
calculateIntensityHistogram(mRGBData, mRedHistogram,
mImageWidth, mImageHeight, 0);
calculateIntensityHistogram(mRGBData, mGreenHistogram,
mImageWidth, mImageHeight, 1);
calculateIntensityHistogram(mRGBData, mBlueHistogram,
mImageWidth, mImageHeight, 2);
// Calculate mean
double imageRedMean = 0, imageGreenMean = 0, imageBlueMean = 0;
double redHistogramSum = 0, greenHistogramSum = 0, blueHistogramSum = 0;
for (int bin = 0; bin < 256; bin++)
{
imageRedMean += mRedHistogram[bin] * bin;
redHistogramSum += mRedHistogram[bin];
imageGreenMean += mGreenHistogram[bin] * bin;
greenHistogramSum += mGreenHistogram[bin];
imageBlueMean += mBlueHistogram[bin] * bin;
blueHistogramSum += mBlueHistogram[bin];
} // bin
imageRedMean /= redHistogramSum;
imageGreenMean /= greenHistogramSum;
imageBlueMean /= blueHistogramSum;
// Calculate second moment
double imageRed2ndMoment = 0, imageGreen2ndMoment = 0, imageBlue2ndMoment = 0;
for (int bin = 0; bin < 256; bin++)
{
imageRed2ndMoment += mRedHistogram[bin] * mBinSquared[bin];
imageGreen2ndMoment += mGreenHistogram[bin] * mBinSquared[bin];
imageBlue2ndMoment += mBlueHistogram[bin] * mBinSquared[bin];
} // bin
imageRed2ndMoment /= redHistogramSum;
imageGreen2ndMoment /= greenHistogramSum;
imageBlue2ndMoment /= blueHistogramSum;
double imageRedStdDev = Math.sqrt( imageRed2ndMoment - imageRedMean*imageRedMean );
double imageGreenStdDev = Math.sqrt( imageGreen2ndMoment - imageGreenMean*imageGreenMean );
double imageBlueStdDev = Math.sqrt( imageBlue2ndMoment - imageBlueMean*imageBlueMean );
// Draw mean
String imageMeanStr = "Mean (R,G,B): " + String.format("%.4g", imageRedMean) + ", " + String.format("%.4g", imageGreenMean) + ", " + String.format("%.4g", imageBlueMean);
canvas.drawText(imageMeanStr, marginWidth+10-1, 30-1, mPaintBlack);
canvas.drawText(imageMeanStr, marginWidth+10+1, 30-1, mPaintBlack);
canvas.drawText(imageMeanStr, marginWidth+10+1, 30+1, mPaintBlack);
canvas.drawText(imageMeanStr, marginWidth+10-1, 30+1, mPaintBlack);
canvas.drawText(imageMeanStr, marginWidth+10, 30, mPaintYellow);
// Draw standard deviation
String imageStdDevStr = "Std Dev (R,G,B): " + String.format("%.4g", imageRedStdDev) + ", " + String.format("%.4g", imageGreenStdDev) + ", " + String.format("%.4g", imageBlueStdDev);
canvas.drawText(imageStdDevStr, marginWidth+10-1, 60-1, mPaintBlack);
canvas.drawText(imageStdDevStr, marginWidth+10+1, 60-1, mPaintBlack);
canvas.drawText(imageStdDevStr, marginWidth+10+1, 60+1, mPaintBlack);
canvas.drawText(imageStdDevStr, marginWidth+10-1, 60+1, mPaintBlack);
canvas.drawText(imageStdDevStr, marginWidth+10, 60, mPaintYellow);
// Draw red intensity histogram
float barMaxHeight = 3000;
float barWidth = ((float)newImageWidth) / 256;
float barMarginHeight = 2;
RectF barRect = new RectF();
barRect.bottom = canvasHeight - 200;
barRect.left = marginWidth;
barRect.right = barRect.left + barWidth;
for (int bin = 0; bin < 256; bin++)
{
float prob = (float)mRedHistogram[bin] / (float)redHistogramSum;
barRect.top = barRect.bottom -
Math.min(80,prob*barMaxHeight) - barMarginHeight;
canvas.drawRect(barRect, mPaintBlack);
barRect.top += barMarginHeight;
canvas.drawRect(barRect, mPaintRed);
barRect.left += barWidth;
barRect.right += barWidth;
} // bin
// Draw green intensity histogram
barRect.bottom = canvasHeight - 100;
barRect.left = marginWidth;
barRect.right = barRect.left + barWidth;
for (int bin = 0; bin < 256; bin++)
{
barRect.top = barRect.bottom - Math.min(80, ((float)mGreenHistogram[bin])/((float)greenHistogramSum) * barMaxHeight) - barMarginHeight;
canvas.drawRect(barRect, mPaintBlack);
barRect.top += barMarginHeight;
canvas.drawRect(barRect, mPaintGreen);
barRect.left += barWidth;
barRect.right += barWidth;
} // bin
// Draw blue intensity histogram
barRect.bottom = canvasHeight;
barRect.left = marginWidth;
barRect.right = barRect.left + barWidth;
for (int bin = 0; bin < 256; bin++)
{
barRect.top = barRect.bottom - Math.min(80, ((float)mBlueHistogram[bin])/((float)blueHistogramSum) * barMaxHeight) - barMarginHeight;
canvas.drawRect(barRect, mPaintBlack);
barRect.top += barMarginHeight;
canvas.drawRect(barRect, mPaintBlue);
barRect.left += barWidth;
barRect.right += barWidth;
} // bin
} // end if statement
super.onDraw(canvas);
} // end onDraw method
static public void decodeYUV420SP(int[] rgb, byte[] yuv420sp, int width, int height) {
final int frameSize = width * height;
for (int j = 0, yp = 0; j < height; j++) {
int uvp = frameSize + (j >> 1) * width, u = 0, v = 0;
for (int i = 0; i < width; i++, yp++) {
int y = (0xff & ((int) yuv420sp[yp])) - 16;
if (y < 0) y = 0;
if ((i & 1) == 0) {
v = (0xff & yuv420sp[uvp++]) - 128;
u = (0xff & yuv420sp[uvp++]) - 128;
}
int y1192 = 1192 * y;
int r = (y1192 + 1634 * v);
int g = (y1192 - 833 * v - 400 * u);
int b = (y1192 + 2066 * u);
if (r < 0) r = 0; else if (r > 262143) r = 262143;
if (g < 0) g = 0; else if (g > 262143) g = 262143;
if (b < 0) b = 0; else if (b > 262143) b = 262143;
rgb[yp] = 0xff000000 | ((r << 6) & 0xff0000) | ((g >> 2) & 0xff00) | ((b >> 10) & 0xff);
}
}
}
static public void decodeYUV420SPGrayscale(int[] rgb, byte[] yuv420sp, int width, int height)
{
final int frameSize = width * height;
for (int pix = 0; pix < frameSize; pix++)
{
int pixVal = (0xff & ((int) yuv420sp[pix])) - 16;
if (pixVal < 0) pixVal = 0;
if (pixVal > 255) pixVal = 255;
rgb[pix] = 0xff000000 | (pixVal << 16) | (pixVal << 8) | pixVal;
} // pix
}
static public void calculateIntensityHistogram(int[] rgb, int[] histogram, int width, int height, int component)
{
for (int bin = 0; bin < 256; bin++)
{
histogram[bin] = 0;
} // bin
if (component == 0) // red
{
for (int pix = 0; pix < width*height; pix += 3)
{
int pixVal = (rgb[pix] >> 16) & 0xff;
histogram[ pixVal ]++;
} // pix
}
else if (component == 1) // green
{
for (int pix = 0; pix < width*height; pix += 3)
{
int pixVal = (rgb[pix] >> 8) & 0xff;
histogram[ pixVal ]++;
} // pix
}
else // blue
{
for (int pix = 0; pix < width*height; pix += 3)
{
int pixVal = rgb[pix] & 0xff;
histogram[ pixVal ]++;
} // pix
}
}
}
This is the class where I wish to create the button which will create the histogram:
public class testrgb extends Activity {
/************************
* PROPERTIES
**********************/
/* Tag for Log */
public static final String TAG = "PiccaFinal.EditPicturesActivity";
/* Images Path */
private String[] _imagesPath;
/* Original Images */
private Bitmap[] _originalBitmaps = new Bitmap[2];
/* Final Filtered Images */
private Bitmap[] _filteredBitmaps = new Bitmap[2];
/* Image View */
private ImageView _filterImageView;
private Preview mPreview;
private DrawOnTop mDrawOnTop;
int[] pixels;
/************************
* ANDROID METHODS
**********************/
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setFormat(PixelFormat.TRANSLUCENT);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_edit_pictures);
Intent intent = getIntent();
_imagesPath = intent.getStringArrayExtra(MainActivity.IMAGES_PATH);
for (int i = MainActivity.LEFT_IMAGE; i <= MainActivity.RIGHT_IMAGE; i++) {
_originalBitmaps[i] = BitmapFactory.decodeFile(_imagesPath[i]);
}
_filterImageView = (ImageView) findViewById(R.id.filter_image_view);
_filterImageView
.setImageBitmap(_originalBitmaps[MainActivity.LEFT_IMAGE]);
// --------------------------------------------------------------------------------
// display_RGB
Button display_RGBButton = (Button) findViewById(R.id.display_RGB);
display_RGBButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//what should I do here
});
}
}
Related
I would like to create an image filter and have read the following Wikipedia article. I wanted to test the example from Wikipedia and get an incorrect result.
https://en.wikipedia.org/wiki/Kernel_(image_processing)
(For some reason I cannot upload images)
Result:
https://imgur.com/FiYFuZS
Expected result:
https://upload.wikimedia.org/wikipedia/commons/2/20/Vd-Rige1.png
I've also read the following source and still do not know how to fix it :/
Bluring a Java buffered image
URL url = new URL("https://upload.wikimedia.org/wikipedia/commons/5/50/Vd-Orig.png");
BufferedImage image = ImageIO.read(url);
float[][] kernel = {
{0, -1, 0},
{-1, 4, -1},
{0, -1, 0}
};
int w = image.getWidth();
int h = image.getHeight();
// Center point
int cx = kernel.length / 2;
int cy = kernel[0].length / 2;
BufferedImage cImage = new BufferedImage(w, h, image.getType());
for (int x = 0; x < w; x++) {
for (int y = 0; y < h; y++) {
float r = 0;
float g = 0;
float b = 0;
for (int dx = -cx; dx <= cx; dx++) {
for (int dy = -cy; dy <= cy; dy++) {
float e = kernel[dx + cx][dy + cy];
int xImage = x + dx;
int yImage = y + dy;
if (xImage < 0 || xImage >= w || yImage < 0 || yImage >= h) {
continue;
}
Color pixel = new Color(image.getRGB(xImage, yImage));
r += pixel.getRed() * e;
g += pixel.getGreen() * e;
b += pixel.getBlue() * e;
}
}
// Boundaries
r = Math.min(255, Math.max(0, r));
g = Math.min(255, Math.max(0, g));
b = Math.min(255, Math.max(0, b));
Color newPixel = new Color((int) r, (int) g, (int) b);
cImage.setRGB(x, y, newPixel.getRGB());
}
}
ImageIO.write(cImage, "png", Files.newOutputStream(Path.of("c.png")));
Displaying different images with different views. For example, sharpen is one. I cannot get it to show Sharpen. I cannot find out how to complete sharpen. I used the professor's code as example.
There are others:
blur 3 x 3
blur 5 x 5
edge detection
grayscale
RGB > GRB
Zoom in
Zoom out
I tried adding 1 to the for loops instead of zero.
Here is code:
PImage source;
PImage destination;
int w = 80;
float[][] matrix_3_3_average = {
{1.0/9.0, 1.0/9.0, 1.0/9.0 },
{1.0/9.0, 1.0/9.0, 1.0/9.0 },
{1.0/9.0, 1.0/9.0, 1.0/9.0 }
};
float[][] matrix_3_3_sharpen =
{ { -1, -1, -1 },
{ -1, 9, -1 },
{ -1, -1, -1 } };
void setup() {
size(200, 200);
source = loadImage("sunflower.jpg");
destination = createImage(source.width, source.height, RGB);
}
void draw() {
destination.loadPixels(); // Tell Processing that we want to read the pixels of the output window
source.loadPixels();
int xStart = constrain(mouseX - w/2, 0, width);
int xEnd = constrain(mouseX + w/2, 0, width);
int yStart = constrain(mouseY - w/2, 0, height);
int yEnd = constrain(mouseY + w/2, 0, height);
if (keyPressed) {
if (key == '0') {
image(source, 0, 0);
for (int x = 1; x < source.width; x++) {
for (int y = 1; y < source.height; y++) {
int loc = x + y * source.width;
if ((x > xStart) && (x < xEnd) && (y > yStart) && (y < yEnd))
destination.pixels[loc] = convolution(x, y, matrix_3_3_average, 3, source);
else
// set the color of the corresponding pixel to the output window to the color of the pixel to the input image
destination.pixels[loc] = source.pixels[loc];
}
}
} else if (key == '1') {
for (int x = 1; x < source.width; x++) {
for (int y = 1; y < source.height; y++) {
int loc = x * y * source.width;
if ((x > xStart) && (x <xEnd) && (y > yStart) && (y < yEnd))
destination.pixels[loc] = convolution(x, y, matrix_3_3_sharpen, 3, source);
else
destination.pixels[loc] = source.pixels[loc];
}
}
}
}
}
color convolution(int x, int y, float[][] matrix, int matrixSize, PImage img) {
int offset = (matrixSize - 1)/2;
float r = 0;
float g = 0;
float b = 0;
for (int i = 0; i < matrixSize; i++) {
for (int j = 0; j < matrixSize; j++) {
int xLoc = x + i - offset;
int yLoc = y + j - offset;
int loc = xLoc * yLoc * img.width;
loc = constrain(loc, 0, img.pixels.length-1);
r = r + matrix[i][j] * red(img.pixels[loc]);
g = g + matrix[i][j] * green(img.pixels[loc]);
b = b + matrix[i][j] * blue(img.pixels[loc]);
}
}
return color(r, g, b);
}
There is an issue when the index of the pixel in the image plan is calculated in the function convolution. The index of an pixel is x + y * width rather than x * width:
int loc = xLoc * yLoc * img.width;</s>
int loc = xLoc + yLoc * img.width;
Copy the source image to the destination at startup and continuously draw the destination image:
void setup() {
size(200, 200);
source = loadImage("C:/temp/flower.jpg"); //source = loadImage("sunflower.jpg");
destination = createImage(source.width, source.height, RGB);
destination.copy(source, 0, 0, source.width, source.height, 0, 0, source.width, source.height);
}
void draw() {
// [...]
image(destination, 0, 0);
}
Use the keyPressed() event to identify if a key was pressed, which starts am image filter:
boolean average = key == '0';
boolean sharpen = key == '1';
void keyPressed() {
average = key == '0';
sharpen = key == '1';
}
When an image filter is performed, the copy the copy the source image to the destination image. Update the pixel in the filtered region. Finally copy the changed destination image to the source image, to be prepared for the next filter operation:
destination.copy(source, 0, 0, source.width, source.height, 0, 0, source.width, source.height);
for (int x = 0; x < source.width; x++) {
for (int y = 0; y < source.height; y++) {
int loc = x + y * source.width;
if (x > xStart && x < xEnd && y > yStart && y < yEnd) {
if ( average )
destination.pixels[loc] = convolution(x, y, matrix_3_3_average, 3, source);
else
destination.pixels[loc] = convolution(x, y, matrix_3_3_sharpen, 3, source);
}
}
}
source.copy(destination, 0, 0, source.width, source.height, 0, 0, source.width, source.height);
See the example, where I applied th suggestions to the code of your question:
PImage source;
PImage destination;
int w = 80;
float[][] matrix_3_3_average = {
{1.0/9.0, 1.0/9.0, 1.0/9.0 },
{1.0/9.0, 1.0/9.0, 1.0/9.0 },
{1.0/9.0, 1.0/9.0, 1.0/9.0 }
};
float[][] matrix_3_3_sharpen =
{ { -1, -1, -1 },
{ -1, 9, -1 },
{ -1, -1, -1 } };
void setup() {
size(200, 200);
source = loadImage("C:/temp/flower.jpg"); //source = loadImage("sunflower.jpg");
destination = createImage(source.width, source.height, RGB);
destination.copy(source, 0, 0, source.width, source.height, 0, 0, source.width, source.height);
}
boolean average = key == '0';
boolean sharpen = key == '1';
void keyPressed() {
average = key == '0';
sharpen = key == '1';
}
void draw() {
int xStart = constrain(mouseX - w/2, 0, width);
int xEnd = constrain(mouseX + w/2, 0, width);
int yStart = constrain(mouseY - w/2, 0, height);
int yEnd = constrain(mouseY + w/2, 0, height);
println(xStart, xEnd, yStart, yEnd);
if (average || sharpen) {
destination.copy(source, 0, 0, source.width, source.height, 0, 0, source.width, source.height);
for (int x = 0; x < source.width; x++) {
for (int y = 0; y < source.height; y++) {
int loc = x + y * source.width;
if (x > xStart && x < xEnd && y > yStart && y < yEnd) {
if ( average )
destination.pixels[loc] = convolution(x, y, matrix_3_3_average, 3, source);
else
destination.pixels[loc] = convolution(x, y, matrix_3_3_sharpen, 3, source);
}
}
}
source.copy(destination, 0, 0, source.width, source.height, 0, 0, source.width, source.height);
average = sharpen = false;
}
image(destination, 0, 0);
}
color convolution(int x, int y, float[][] matrix, int matrixSize, PImage img) {
int offset = (matrixSize - 1)/2;
float r = 0;
float g = 0;
float b = 0;
for (int i = 0; i < matrixSize; i++) {
for (int j = 0; j < matrixSize; j++) {
int xLoc = x + i - offset;
int yLoc = y + j - offset;
int loc = xLoc + yLoc * img.width;
loc = constrain(loc, 0, img.pixels.length-1);
r = r + matrix[i][j] * red(img.pixels[loc]);
g = g + matrix[i][j] * green(img.pixels[loc]);
b = b + matrix[i][j] * blue(img.pixels[loc]);
}
}
return color(r, g, b);
}
I have little experience with java programming, but I know my way around it a little. I want to pick up a project that was left behind by someone else. I was doing well fixing other errors here and there, but this one stumped me. Here it is:
javax.imageio.IIOException: Can't read input file!
at javax.imageio.ImageIO.read(Unknown Source)
at Replacer.main(Replacer.java:19)
To my surprise, the program still opened. However, when I tried to open a picture, this happened, and displayed a picture of 0 x 0 pixels:
Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException:
2147483647
at ImageEditor.resize(ImageEditor.java:384)
at ImageEditor.resize(ImageEditor.java:308)
at ImageFrame.setImage(ImageFrame.java:438)
at ImageFrame.actionPerformed(ImageFrame.java:765)
at java.awt.Button.processActionEvent(Unknown Source)
at java.awt.Button.processEvent(Unknown Source)
at java.awt.Component.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.awt.EventQueue.access$500(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionP
rivilege(Unknown Source)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionP
rivilege(Unknown Source)
at java.awt.EventQueue$4.run(Unknown Source)
at java.awt.EventQueue$4.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionP
rivilege(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)
Replacer:
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.PrintStream;
import javax.imageio.ImageIO;
public class Replacer
{
public static void main(String[] args)
{
BufferedImage i = null;
BufferedImage i2 = null;
Color[][] blockColors = new Color[16][16];
ImageFrame b = new ImageFrame(i);
try
{
i2 = ImageIO.read(new File("terrain.png"));
int blockSize = i2.getWidth(b) / 16;
System.out.println("Analyzing terrain.png");
int[] buffer = ImageEditor.returnBuffer(i2, b);
int width = i2.getWidth(b);
for (int j = 0; j < 16; j++) {
for (int k = 0; k < 16; k++) {
if ((j <= 2) || (k <= 8))
{
int[] i3 = ImageEditor.crop(buffer, width, width, b, j * blockSize, k * blockSize, blockSize, blockSize);
blockColors[j][k] = ImageEditor.getAverageColor(i3, b);
}
}
}
Color[] c2 = new Color[100];
c2[0] = blockColors[1][8];
c2[1] = blockColors[2][10];
c2[2] = blockColors[1][11];
c2[3] = blockColors[1][9];
c2[4] = blockColors[1][7];
c2[5] = blockColors[0][4];
c2[6] = blockColors[2][13];
c2[7] = blockColors[1][13];
c2[8] = blockColors[1][12];
c2[9] = blockColors[2][7];
c2[10] = blockColors[2][11];
c2[11] = blockColors[2][8];
c2[12] = blockColors[2][9];
c2[13] = blockColors[2][12];
c2[14] = blockColors[1][14];
c2[15] = blockColors[1][10];
c2[16] = blockColors[1][0];
c2[17] = blockColors[2][0];
c2[18] = blockColors[2][1];
c2[19] = blockColors[3][1];
c2[20] = blockColors[8][4];
c2[21] = blockColors[5][2];
c2[22] = blockColors[4][2];
c2[23] = blockColors[6][7];
c2[24] = blockColors[4][0];
c2[25] = blockColors[0][1];
c2[26] = blockColors[0][11];
c2[27] = blockColors[7][0];
c2[28] = blockColors[6][1];
c2[29] = blockColors[7][1];
c2[30] = blockColors[8][1];
c2[31] = blockColors[0][9];
c2[32] = blockColors[10][4];
c2[33] = blockColors[9][6];
c2[34] = blockColors[7][6];
c2[35] = blockColors[8][6];
c2[36] = blockColors[2][4];
c2[37] = blockColors[6][3];
c2[38] = blockColors[1][1];
c2[39] = blockColors[5][1];
c2[40] = blockColors[4][1];
c2[41] = blockColors[4][7];
c2[42] = blockColors[5][7];
c2[43] = blockColors[0][3];
c2[44] = blockColors[3][4];
c2[45] = blockColors[8][8];
c2[46] = blockColors[8][9];
c2[47] = blockColors[8][10];
c2[48] = blockColors[8][11];
c2[49] = blockColors[8][12];
for (int j = 0; j < c2.length / 2; j++)
{
double shadowRed = 0.892D * c2[j].getRed() + 0.5D;
double shadowGreen = 0.892D * c2[j].getGreen() + 0.5D;
double shadowBlue = 0.892D * c2[j].getBlue() + 0.5D;
c2[(50 + j)] = new Color((int)shadowRed, (int)shadowGreen, (int)shadowBlue);
}
for (int j = 0; j < c2.length; j++) {
System.out.println("colors[" + j + "] = new Color(" + c2[j].getRed() + "," + c2[j].getGreen() + "," + c2[j].getBlue() + ");");
}
b.setColors(c2);
System.out.println("Done");
}
catch (Exception e)
{
e.printStackTrace();
}
b.repaint();
}
}
ImageEditor:
import java.awt.Color;
import java.awt.Component;
import java.awt.Image;
import java.awt.MediaTracker;
import java.awt.image.MemoryImageSource;
import java.awt.image.PixelGrabber;
import java.io.PrintStream;
public class ImageEditor
{
public static int[] returnBuffer(Image i, Component c)
{
MediaTracker tracker = new MediaTracker(c);
tracker.addImage(i, 0);
try
{
tracker.waitForAll();
}
catch (Exception e)
{
System.out.println("Image loading interrupted");
}
int width = i.getWidth(c);
int height = i.getHeight(c);
int[] buffer = new int[width * height];
PixelGrabber grabber = new PixelGrabber(i, 0, 0, width, height, buffer, 0, width);
try
{
grabber.grabPixels();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
return buffer;
}
public static Image simplifyColors(int width, int height, int[] buffer, Component c, Color[] colors)
{
double[] w = new double[colors.length];
for (int k = 0; k < w.length; k++) {
w[k] = 1.0D;
}
return simplifyColors(width, height, buffer, c, colors, w);
}
public static Image simplifyColors(int width, int height, int[] buffer, Component c, Color[] colors, double[] weights)
{
int[] simple = new int[buffer.length];
for (int j = 0; j < buffer.length; j++)
{
int minDiff = 10000000;
Color current = new Color(buffer[j], true);
Color col = Color.black;
for (int k = 0; k < colors.length; k++)
{
Color test = colors[k];
double w = weights[k];
if (test != null)
{
int diff = (int)((Math.pow(test.getRed() - current.getRed(), 2.0D) + Math.pow(test.getGreen() - current.getGreen(), 2.0D) + Math.pow(test.getBlue() - current.getBlue(), 2.0D)) / w);
if (diff < minDiff)
{
col = test;
minDiff = diff;
}
}
}
if (current.getAlpha() >= 128) {
simple[j] = col.getRGB();
} else {
simple[j] = new Color(255, 255, 255, 0).getRGB();
}
}
return c.createImage(new MemoryImageSource(width, height, simple, 0, width));
}
public static Image simplifyColors2(Image i, int[] buffer, Component c, Color[] colors)
{
double[] w = new double[colors.length];
for (int k = 0; k < w.length; k++) {
w[k] = 1.0D;
}
return simplifyColors2(i, buffer, c, colors, w);
}
public static Image simplifyColors2(Image i, int[] buffer, Component c, Color[] colors, double[] weights)
{
int height = i.getHeight(c);
int width = i.getWidth(c);
int[] simple = new int[buffer.length];
float[] hsb1 = new float[3];
float[] hsb2 = new float[3];
for (int j = 0; j < buffer.length; j++)
{
int minDiff = 10000000;
Color current = new Color(buffer[j], true);
hsb1 = Color.RGBtoHSB(current.getRed(), current.getGreen(), current.getBlue(), null);
Color col = Color.black;
for (int k = 0; k < colors.length; k++)
{
Color test = colors[k];
if (test != null)
{
hsb2 = Color.RGBtoHSB(test.getRed(), test.getGreen(), test.getBlue(), null);
int diff = (int)(Math.pow(hsb1[0] - hsb2[0], 2.0D) + Math.pow(hsb1[1] - hsb2[1], 2.0D) + Math.pow(hsb1[2] - hsb2[2], 2.0D));
if (diff < minDiff)
{
col = test;
minDiff = diff;
}
}
}
if (current.getAlpha() >= 128) {
simple[j] = col.getRGB();
} else {
simple[j] = new Color(255, 255, 255, 0).getRGB();
}
}
return c.createImage(new MemoryImageSource(width, height, simple, 0, width));
}
public static Image simplifyColors3(int width, int height, int[] buffer2, Component c, Color[] colors, double[] weights)
{
int[] buffer = (int[])buffer2.clone();
int[] simple = new int[buffer.length];
for (int j = 0; j < buffer.length; j++)
{
int minDiff = 10000000;
Color current = new Color(buffer[j], true);
Color col = Color.black;
for (int k = 0; k < colors.length; k++)
{
if (current.getAlpha() == 0)
{
col = new Color(255, 255, 255, 0);
break;
}
Color test = colors[k];
double w = weights[k];
if (test != null)
{
int diff = (int)((Math.pow(test.getRed() - current.getRed(), 2.0D) + Math.pow(test.getGreen() - current.getGreen(), 2.0D) + Math.pow(test.getBlue() - current.getBlue(), 2.0D)) / w);
if (diff < minDiff)
{
col = test;
minDiff = diff;
}
}
}
int quantErrorR = current.getRed() - col.getRed();
int quantErrorG = current.getGreen() - col.getGreen();
int quantErrorB = current.getBlue() - col.getBlue();
if ((j + 1) % width != 0)
{
Color x = new Color(buffer[(j + 1)], true);
Color y = new Color(Math.max(0, Math.min(x.getRed() + col.getAlpha() / 255 * quantErrorR * 7 / 16, 255)), Math.max(0, Math.min(x.getGreen() + col.getAlpha() / 255 * quantErrorG * 7 / 16, 255)), Math.max(0, Math.min(x.getBlue() + col.getAlpha() / 255 * quantErrorB * 7 / 16, 255)), x.getAlpha());
buffer[(j + 1)] = y.getRGB();
}
if (((j - 1) % width != 0) && (j - 1 + width < buffer.length))
{
Color x = new Color(buffer[(j - 1 + width)], true);
Color y = new Color(Math.max(0, Math.min(x.getRed() + col.getAlpha() / 255 * quantErrorR * 3 / 16, 255)), Math.max(0, Math.min(x.getGreen() + col.getAlpha() / 255 * quantErrorG * 3 / 16, 255)), Math.max(0, Math.min(x.getBlue() + col.getAlpha() / 255 * quantErrorB * 3 / 16, 255)), x.getAlpha());
buffer[(j - 1 + width)] = y.getRGB();
}
if (j + width < buffer.length)
{
Color x = new Color(buffer[(j + width)], true);
Color y = new Color(Math.max(0, Math.min(x.getRed() + col.getAlpha() / 255 * quantErrorR * 5 / 16, 255)), Math.max(0, Math.min(x.getGreen() + col.getAlpha() / 255 * quantErrorG * 5 / 16, 255)), Math.max(0, Math.min(x.getBlue() + col.getAlpha() / 255 * quantErrorB * 5 / 16, 255)), x.getAlpha());
buffer[(j + width)] = y.getRGB();
}
if (((j + 1) % width != 0) && (j + 1 + width < buffer.length))
{
Color x = new Color(buffer[(j + 1 + width)], true);
Color y = new Color(Math.max(0, Math.min(x.getRed() + col.getAlpha() / 255 * quantErrorR * 1 / 16, 255)), Math.max(0, Math.min(x.getGreen() + col.getAlpha() / 255 * quantErrorG * 1 / 16, 255)), Math.max(0, Math.min(x.getBlue() + col.getAlpha() / 255 * quantErrorB * 1 / 16, 255)), x.getAlpha());
buffer[(j + 1 + width)] = y.getRGB();
}
if (current.getAlpha() >= 128) {
simple[j] = col.getRGB();
} else {
simple[j] = new Color(255, 255, 255, 0).getRGB();
}
}
return c.createImage(new MemoryImageSource(width, height, simple, 0, width));
}
public static Image shadowColors(int width, int height, int[] buffer, Component c, Color[] colors, double[] weights)
{
int[] simple = new int[buffer.length];
double k2 = 0.0D;
for (int j = 0; j < buffer.length; j++)
{
int minDiff = 10000000;
Color current = new Color(buffer[j], true);
Color col = Color.black;
for (int k = 0; k < colors.length; k++)
{
Color test = colors[k];
double w = weights[k];
if (test != null)
{
int diff = (int)((Math.pow(test.getRed() - current.getRed(), 2.0D) + Math.pow(test.getGreen() - current.getGreen(), 2.0D) + Math.pow(test.getBlue() - current.getBlue(), 2.0D)) / w);
if (diff < minDiff)
{
col = test;
k2 = k;
minDiff = diff;
}
}
}
if (current.getAlpha() >= 128)
{
if (k2 < colors.length / 2) {
simple[j] = Color.WHITE.getRGB();
} else {
simple[j] = Color.BLACK.getRGB();
}
}
else {
simple[j] = new Color(255, 255, 255, 0).getRGB();
}
}
return c.createImage(new MemoryImageSource(width, height, simple, 0, width));
}
public static Image shadowColors3(int width, int height, int[] buffer2, Component c, Color[] colors, double[] weights)
{
int[] buffer = (int[])buffer2.clone();
int[] simple = new int[buffer.length];
double k2 = 0.0D;
for (int j = 0; j < buffer.length; j++)
{
int minDiff = 10000000;
Color current = new Color(buffer[j], true);
Color col = Color.black;
for (int k = 0; k < colors.length; k++)
{
if (current.getAlpha() == 0)
{
col = new Color(255, 255, 255, 0);
break;
}
Color test = colors[k];
double w = weights[k];
if (test != null)
{
int diff = (int)((Math.pow(test.getRed() - current.getRed(), 2.0D) + Math.pow(test.getGreen() - current.getGreen(), 2.0D) + Math.pow(test.getBlue() - current.getBlue(), 2.0D)) / w);
if (diff < minDiff)
{
col = test;
minDiff = diff;
k2 = k;
}
}
}
int quantErrorR = current.getRed() - col.getRed();
int quantErrorG = current.getGreen() - col.getGreen();
int quantErrorB = current.getBlue() - col.getBlue();
if ((j + 1) % width != 0)
{
Color x = new Color(buffer[(j + 1)], true);
Color y = new Color(Math.max(0, Math.min(x.getRed() + col.getAlpha() / 255 * quantErrorR * 7 / 16, 255)), Math.max(0, Math.min(x.getGreen() + col.getAlpha() / 255 * quantErrorG * 7 / 16, 255)), Math.max(0, Math.min(x.getBlue() + col.getAlpha() / 255 * quantErrorB * 7 / 16, 255)), x.getAlpha());
buffer[(j + 1)] = y.getRGB();
}
if (((j - 1) % width != 0) && (j - 1 + width < buffer.length))
{
Color x = new Color(buffer[(j - 1 + width)], true);
Color y = new Color(Math.max(0, Math.min(x.getRed() + col.getAlpha() / 255 * quantErrorR * 3 / 16, 255)), Math.max(0, Math.min(x.getGreen() + col.getAlpha() / 255 * quantErrorG * 3 / 16, 255)), Math.max(0, Math.min(x.getBlue() + col.getAlpha() / 255 * quantErrorB * 3 / 16, 255)), x.getAlpha());
buffer[(j - 1 + width)] = y.getRGB();
}
if (j + width < buffer.length)
{
Color x = new Color(buffer[(j + width)], true);
Color y = new Color(Math.max(0, Math.min(x.getRed() + col.getAlpha() / 255 * quantErrorR * 5 / 16, 255)), Math.max(0, Math.min(x.getGreen() + col.getAlpha() / 255 * quantErrorG * 5 / 16, 255)), Math.max(0, Math.min(x.getBlue() + col.getAlpha() / 255 * quantErrorB * 5 / 16, 255)), x.getAlpha());
buffer[(j + width)] = y.getRGB();
}
if (((j + 1) % width != 0) && (j + 1 + width < buffer.length))
{
Color x = new Color(buffer[(j + 1 + width)], true);
Color y = new Color(Math.max(0, Math.min(x.getRed() + col.getAlpha() / 255 * quantErrorR * 1 / 16, 255)), Math.max(0, Math.min(x.getGreen() + col.getAlpha() / 255 * quantErrorG * 1 / 16, 255)), Math.max(0, Math.min(x.getBlue() + col.getAlpha() / 255 * quantErrorB * 1 / 16, 255)), x.getAlpha());
buffer[(j + 1 + width)] = y.getRGB();
}
if (current.getAlpha() >= 128)
{
if (k2 < colors.length / 2) {
simple[j] = Color.WHITE.getRGB();
} else {
simple[j] = Color.BLACK.getRGB();
}
}
else {
simple[j] = new Color(255, 255, 255, 0).getRGB();
}
}
return c.createImage(new MemoryImageSource(width, height, simple, 0, width));
}
public static Image resize(Image i, int[] buffer, Component c, int newDim)
{
int h = i.getHeight(c);
int w = i.getWidth(c);
if (w < h) {
return resize(i, buffer, c, newDim, (int)(newDim * 1.0D * w / h));
}
return resize(i, buffer, c, (int)(newDim * 1.0D * h / w), newDim);
}
public static int getResizedHeight(Image i, Component c, int newDim)
{
int h = i.getHeight(c);
int w = i.getWidth(c);
if (w < h) {
return newDim;
}
return (int)(newDim * 1.0D * h / w);
}
public static int getResizedWidth(Image i, Component c, int newDim)
{
int h = i.getHeight(c);
int w = i.getWidth(c);
if (w < h) {
return (int)(newDim * 1.0D * w / h);
}
return newDim;
}
public static int[] resizebuff(Image i, int[] buffer, Component c, int newDim)
{
int h = i.getHeight(c);
int w = i.getWidth(c);
if (w < h) {
return resizebuff(i, buffer, c, newDim, (int)(newDim * 1.0D * w / h));
}
return resizebuff(i, buffer, c, (int)(newDim * 1.0D * h / w), newDim);
}
public static Image resize2(Image i, int[] buffer, Component c, int newDim)
{
int h = i.getHeight(c);
int w = i.getWidth(c);
if (w < h) {
return resize2(i, buffer, c, newDim, (int)(newDim * 1.0D * w / h));
}
return resize2(i, buffer, c, (int)(newDim * 1.0D * h / w), newDim);
}
public static int[] resize2buff(Image i, int[] buffer, Component c, int newDim)
{
int h = i.getHeight(c);
int w = i.getWidth(c);
if (w < h) {
return resize2buff(i, buffer, c, newDim, (int)(newDim * 1.0D * w / h));
}
return resize2buff(i, buffer, c, (int)(newDim * 1.0D * h / w), newDim);
}
public static Image resize(Image i, int[] buffer, Component c, int newHeight, int newWidth)
{
if (newHeight < 2) {
newHeight = 2;
}
if (newWidth < 2) {
newWidth = 2;
}
int height = i.getHeight(c);
int width = i.getWidth(c);
if ((height == newHeight) && (width == newWidth)) {
return i;
}
int[] resized = new int[newHeight * newWidth];
double hRatio = newHeight / height;
double wRatio = newWidth / width;
for (int y = 0; y < newHeight; y++) {
for (int x = 0; x < newWidth; x++)
{
int oldX = (int)(x / wRatio);
int oldY = (int)(y / hRatio);
resized[(y * newWidth + x)] = buffer[(oldY * width + oldX)];
}
}
return c.createImage(new MemoryImageSource(newWidth, newHeight, resized, 0, newWidth));
}
public static int[] resizebuff(Image i, int[] buffer, Component c, int newHeight, int newWidth)
{
if (newHeight < 2) {
newHeight = 2;
}
if (newWidth < 2) {
newWidth = 2;
}
int height = i.getHeight(c);
int width = i.getWidth(c);
if ((height == newHeight) && (width == newWidth)) {
return buffer;
}
int[] resized = new int[newHeight * newWidth];
double hRatio = newHeight / height;
double wRatio = newWidth / width;
for (int y = 0; y < newHeight; y++) {
for (int x = 0; x < newWidth; x++)
{
int oldX = (int)(x / wRatio);
int oldY = (int)(y / hRatio);
resized[(y * newWidth + x)] = buffer[(oldY * width + oldX)];
}
}
return resized;
}
public static Image resize2(Image i, int[] buffer, Component c, int newHeight, int newWidth)
{
if (newHeight < 2) {
newHeight = 2;
}
if (newWidth < 2) {
newWidth = 2;
}
int height = i.getHeight(c);
int width = i.getWidth(c);
if ((height == newHeight) && (width == newWidth)) {
return i;
}
int[] resized = new int[newHeight * newWidth];
double hRatio = newHeight / height;
double wRatio = newWidth / width;
if ((hRatio > 1.0D) || (wRatio > 1.0D)) {
return resize(i, buffer, c, newHeight, newWidth);
}
for (int y = 0; y < newHeight; y++) {
for (int x = 0; x < newWidth; x++)
{
int k = 0;
double oldC = 0.0D;
double oldRed = 0.0D;
double oldGreen = 0.0D;
double oldBlue = 0.0D;
double oldAlpha = 0.0D;
for (int q = (int)(x / wRatio); q < (int)((x + 1) / wRatio); q++) {
for (int j = (int)(y / hRatio); j < (int)((y + 1) / hRatio); j++)
{
Color oldColor = new Color(buffer[(j * width + q)], true);
oldRed = (oldRed * k + oldColor.getRed()) / (k + 1);
oldGreen = (oldGreen * k + oldColor.getGreen()) / (k + 1);
oldBlue = (oldBlue * k + oldColor.getBlue()) / (k + 1);
oldAlpha = (oldAlpha * k + oldColor.getAlpha()) / (k + 1);
k++;
}
}
resized[(y * newWidth + x)] = new Color((int)oldRed, (int)oldGreen, (int)oldBlue, (int)oldAlpha).getRGB();
}
}
return c.createImage(new MemoryImageSource(newWidth, newHeight, resized, 0, newWidth));
}
public static int[] resize2buff(Image i, int[] buffer, Component c, int newHeight, int newWidth)
{
if (newHeight < 2) {
newHeight = 2;
}
if (newWidth < 2) {
newWidth = 2;
}
int height = i.getHeight(c);
int width = i.getWidth(c);
if ((height == newHeight) && (width == newWidth)) {
return buffer;
}
int[] resized = new int[newHeight * newWidth];
double hRatio = newHeight / height;
double wRatio = newWidth / width;
if ((hRatio > 1.0D) || (wRatio > 1.0D)) {
return resizebuff(i, buffer, c, newHeight, newWidth);
}
for (int y = 0; y < newHeight; y++) {
for (int x = 0; x < newWidth; x++)
{
int k = 0;
double oldC = 0.0D;
double oldRed = 0.0D;
double oldGreen = 0.0D;
double oldBlue = 0.0D;
double oldAlpha = 0.0D;
for (int q = (int)(x / wRatio); q < (int)((x + 1) / wRatio); q++) {
for (int j = (int)(y / hRatio); j < (int)((y + 1) / hRatio); j++)
{
Color oldColor = new Color(buffer[(j * width + q)], true);
oldRed = (oldRed * k + oldColor.getRed()) / (k + 1);
oldGreen = (oldGreen * k + oldColor.getGreen()) / (k + 1);
oldBlue = (oldBlue * k + oldColor.getBlue()) / (k + 1);
oldAlpha = (oldAlpha * k + oldColor.getAlpha()) / (k + 1);
k++;
}
}
resized[(y * newWidth + x)] = new Color((int)oldRed, (int)oldGreen, (int)oldBlue, (int)oldAlpha).getRGB();
}
}
return resized;
}
public static int[] countColors(int[] buffer, Component c, Color[] colors)
{
int[] count = new int[colors.length];
for (int k = 0; k < count.length; k++) {
count[k] = 0;
}
Color col = Color.BLACK;
for (int j = 0; j < buffer.length; j++)
{
col = new Color(buffer[j]);
for (int k = 0; k < colors.length; k++) {
if ((colors[k] != null) && (colors[k].getRGB() == col.getRGB())) {
count[k] += 1;
}
}
}
return count;
}
(Had to cut it off b/c of character limit)
EDIT: Turns out the first error doesn't matter. The program tries to run textures from a separate file. If it isn't found, it skips it.
Any help is appreciated.
Addressing your second issue with the stack trace:
This line is your issue:
resized[(y * newWidth + x)] = buffer[(oldY * width + oldX)];
Specifically this part resized[(y * newWidth + x)] because [y * newWidth + x] can be far bigger than what resized allows.
Let's assume the image is 100x50 (WxH), this means that int[] resized = new int[newHeight * newWidth]; will create a new array that is 5000 long.
However the for loops will create something much higher:
for (int y = 0; y < newHeight; y++) in this instance y will go as high as newHeight or 100
vfor (int x = 0; x < newWidth; x++)in this instanceywill go as high asnewWidth` or 50
So:
resized[(y * newWidth + x)] = something; will be an issue because 100 * 100 + 50 can be as large as 10050, that is far bigger than 5000.
The solution is to make a larger resized array, or to rethink your for loops.
I have to convert an image to a pencil sketch in android.
I used the concepts of the cataleno framework and colorDodge function mentioned in one of the previous questions.
This is my function:
public void onBwClick(View v) {
Bitmap bm = ((BitmapDrawable) mImageView.getDrawable()).getBitmap();
FastBitmap fb = new FastBitmap(bm);
Grayscale g = new Grayscale();
g.applyInPlace(fb);
Invert i = new Invert();
i.applyInPlace(fb);
GaussianBlur gb = new GaussianBlur();
gb.applyInPlace(fb);
FastBitmap xb = new FastBitmap(bm);
Grayscale gs = new Grayscale();
g.applyInPlace(xb);
Bitmap result = colorDodgeBlend(fb.toBitmap(), xb.toBitmap());
mImageView.setImageBitmap(result);
}
This is the colorDodgeBlend function:
public Bitmap colorDodgeBlend(Bitmap source, Bitmap layer) {
Log.d("", "logger enter colorDodgeBlend");
Bitmap base = source.copy(Config.ARGB_8888, true);
Bitmap blend = layer.copy(Config.ARGB_8888, false);
IntBuffer buffBase = IntBuffer.allocate(base.getWidth()
* base.getHeight());
base.copyPixelsToBuffer(buffBase);
buffBase.rewind();
IntBuffer buffBlend = IntBuffer.allocate(blend.getWidth()
* blend.getHeight());
blend.copyPixelsToBuffer(buffBlend);
buffBlend.rewind();
IntBuffer buffOut = IntBuffer.allocate(base.getWidth()
* base.getHeight());
buffOut.rewind();
while (buffOut.position() < buffOut.limit()) {
int filterInt = buffBlend.get();
int srcInt = buffBase.get();
int redValueFilter = Color.red(filterInt);
int greenValueFilter = Color.green(filterInt);
int blueValueFilter = Color.blue(filterInt);
int redValueSrc = Color.red(srcInt);
int greenValueSrc = Color.green(srcInt);
int blueValueSrc = Color.blue(srcInt);
int redValueFinal = colordodge(redValueFilter, redValueSrc);
int greenValueFinal = colordodge(greenValueFilter, greenValueSrc);
int blueValueFinal = colordodge(blueValueFilter, blueValueSrc);
int pixel = Color.argb(255, redValueFinal, greenValueFinal,
blueValueFinal);
float[] hsv = new float[3];
Color.colorToHSV(pixel, hsv);
hsv[1] = 0.0f;
float top = VALUE_TOP; // Setting this as 0.95f gave the best result so far
if (hsv[2] <= top) {
hsv[2] = 0.0f;
} else {
hsv[2] = 1.0f;
}
pixel = Color.HSVToColor(hsv);
buffOut.put(pixel);
}
buffOut.rewind();
base.copyPixelsFromBuffer(buffOut);
blend.recycle();
Log.d("", "logger executed colorDodgeBlend");
return base;
}
Finally this is the output I am getting:
!https://drive.google.com/file/d/0B9LDDNqlgTC1U3E3QXdiejk1Q28/edit?usp=sharing
This is what i desire:
!https://drive.google.com/file/d/0B9LDDNqlgTC1QkFPSmJFOXMyaUU/edit?usp=sharing
Kindly help me out in this.
You Need to do Below 2 Things.
1.. Use This Code for Blur Effect With Radius = 10 or more.
public Bitmap fastblur(Bitmap sentBitmap, int radius) {
Bitmap bitmap = sentBitmap.copy(sentBitmap.getConfig(), true);
if (radius < 1) {
return (null);
}
int w = bitmap.getWidth();
int h = bitmap.getHeight();
int[] pix = new int[w * h];
Log.e("pix", w + " " + h + " " + pix.length);
bitmap.getPixels(pix, 0, w, 0, 0, w, h);
int wm = w - 1;
int hm = h - 1;
int wh = w * h;
int div = radius + radius + 1;
int r[] = new int[wh];
int g[] = new int[wh];
int b[] = new int[wh];
int rsum, gsum, bsum, x, y, i, p, yp, yi, yw;
int vmin[] = new int[Math.max(w, h)];
int divsum = (div + 1) >> 1;
divsum *= divsum;
int dv[] = new int[256 * divsum];
for (i = 0; i < 256 * divsum; i++) {
dv[i] = (i / divsum);
}
yw = yi = 0;
int[][] stack = new int[div][3];
int stackpointer;
int stackstart;
int[] sir;
int rbs;
int r1 = radius + 1;
int routsum, goutsum, boutsum;
int rinsum, ginsum, binsum;
for (y = 0; y < h; y++) {
rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
for (i = -radius; i <= radius; i++) {
p = pix[yi + Math.min(wm, Math.max(i, 0))];
sir = stack[i + radius];
sir[0] = (p & 0xff0000) >> 16;
sir[1] = (p & 0x00ff00) >> 8;
sir[2] = (p & 0x0000ff);
rbs = r1 - Math.abs(i);
rsum += sir[0] * rbs;
gsum += sir[1] * rbs;
bsum += sir[2] * rbs;
if (i > 0) {
rinsum += sir[0];
ginsum += sir[1];
binsum += sir[2];
} else {
routsum += sir[0];
goutsum += sir[1];
boutsum += sir[2];
}
}
stackpointer = radius;
for (x = 0; x < w; x++) {
r[yi] = dv[rsum];
g[yi] = dv[gsum];
b[yi] = dv[bsum];
rsum -= routsum;
gsum -= goutsum;
bsum -= boutsum;
stackstart = stackpointer - radius + div;
sir = stack[stackstart % div];
routsum -= sir[0];
goutsum -= sir[1];
boutsum -= sir[2];
if (y == 0) {
vmin[x] = Math.min(x + radius + 1, wm);
}
p = pix[yw + vmin[x]];
sir[0] = (p & 0xff0000) >> 16;
sir[1] = (p & 0x00ff00) >> 8;
sir[2] = (p & 0x0000ff);
rinsum += sir[0];
ginsum += sir[1];
binsum += sir[2];
rsum += rinsum;
gsum += ginsum;
bsum += binsum;
stackpointer = (stackpointer + 1) % div;
sir = stack[(stackpointer) % div];
routsum += sir[0];
goutsum += sir[1];
boutsum += sir[2];
rinsum -= sir[0];
ginsum -= sir[1];
binsum -= sir[2];
yi++;
}
yw += w;
}
for (x = 0; x < w; x++) {
rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
yp = -radius * w;
for (i = -radius; i <= radius; i++) {
yi = Math.max(0, yp) + x;
sir = stack[i + radius];
sir[0] = r[yi];
sir[1] = g[yi];
sir[2] = b[yi];
rbs = r1 - Math.abs(i);
rsum += r[yi] * rbs;
gsum += g[yi] * rbs;
bsum += b[yi] * rbs;
if (i > 0) {
rinsum += sir[0];
ginsum += sir[1];
binsum += sir[2];
} else {
routsum += sir[0];
goutsum += sir[1];
boutsum += sir[2];
}
if (i < hm) {
yp += w;
}
}
yi = x;
stackpointer = radius;
for (y = 0; y < h; y++) {
// Preserve alpha channel: ( 0xff000000 & pix[yi] )
pix[yi] = (0xff000000 & pix[yi]) | (dv[rsum] << 16)
| (dv[gsum] << 8) | dv[bsum];
rsum -= routsum;
gsum -= goutsum;
bsum -= boutsum;
stackstart = stackpointer - radius + div;
sir = stack[stackstart % div];
routsum -= sir[0];
goutsum -= sir[1];
boutsum -= sir[2];
if (x == 0) {
vmin[y] = Math.min(y + r1, hm) * w;
}
p = x + vmin[y];
sir[0] = r[p];
sir[1] = g[p];
sir[2] = b[p];
rinsum += sir[0];
ginsum += sir[1];
binsum += sir[2];
rsum += rinsum;
gsum += ginsum;
bsum += binsum;
stackpointer = (stackpointer + 1) % div;
sir = stack[stackpointer];
routsum += sir[0];
goutsum += sir[1];
boutsum += sir[2];
rinsum -= sir[0];
ginsum -= sir[1];
binsum -= sir[2];
yi += w;
}
}
Log.e("pix", w + " " + h + " " + pix.length);
bitmap.setPixels(pix, 0, w, 0, 0, w, h);
return (bitmap);
}
2.. Remove Below Code from colorDodgeBlend Function
float[] hsv = new float[3];
Color.colorToHSV(pixel, hsv);
hsv[1] = 0.0f;
float top = VALUE_TOP; // Setting this as 0.95f gave the best result so far
if (hsv[2] <= top) {
hsv[2] = 0.0f;
} else {
hsv[2] = 1.0f;
}
pixel = Color.HSVToColor(hsv);
So I'm trying to blur an image as fast as possible(instant feel like),
as the activity needs to be updated as I press the Blur button.
The problem I am having is that, I cannot find a Blur that works quick enough...
Note: The blur, preferably a Gaussian blur, doesn't need to be the best quality at all..
I tried out the following, but it takes a few seconds, is there anyway this code could be made to run quicker in sacrifice of quality ? Or are there any other alternatives?
I would look into GPU stuff, but this blur is really just an effect related to the UI and only happens when I press open a transparent activity sized as a small box...
Any Ideas?
static Bitmap fastblur(Bitmap sentBitmap, int radius, int fromX, int fromY,
int width, int height) {
// Stack Blur v1.0 from
// http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html
//
// Java Author: Mario Klingemann <mario at quasimondo.com>
// http://incubator.quasimondo.com
// created Feburary 29, 2004
// Android port : Yahel Bouaziz <yahel at kayenko.com>
// http://www.kayenko.com
// ported april 5th, 2012
// This is a compromise between Gaussian Blur and Box blur
// It creates much better looking blurs than Box Blur, but is
// 7x faster than my Gaussian Blur implementation.
//
// I called it Stack Blur because this describes best how this
// filter works internally: it creates a kind of moving stack
// of colors whilst scanning through the image. Thereby it
// just has to add one new block of color to the right side
// of the stack and remove the leftmost color. The remaining
// colors on the topmost layer of the stack are either added on
// or reduced by one, depending on if they are on the right or
// on the left side of the stack.
//
// If you are using this algorithm in your code please add
// the following line:
//
// Stack Blur Algorithm by Mario Klingemann <mario#quasimondo.com>
Bitmap bitmap = sentBitmap.copy(sentBitmap.getConfig(), true);
if (radius < 1) {
return (null);
}
int w = width;
int h = height;
int[] pix = new int[w * h];
bitmap.getPixels(pix, 0, w, fromX, fromY, w, h);
int wm = w - 1;
int hm = h - 1;
int wh = w * h;
int div = radius + radius + 1;
int r[] = new int[wh];
int g[] = new int[wh];
int b[] = new int[wh];
int rsum, gsum, bsum, x, y, i, p, yp, yi, yw;
int vmin[] = new int[Math.max(w, h)];
int divsum = (div + 1) >> 1;
divsum *= divsum;
int dv[] = new int[256 * divsum];
for (i = 0; i < 256 * divsum; i++) {
dv[i] = (i / divsum);
}
yw = yi = 0;
int[][] stack = new int[div][3];
int stackpointer;
int stackstart;
int[] sir;
int rbs;
int r1 = radius + 1;
int routsum, goutsum, boutsum;
int rinsum, ginsum, binsum;
int originRadius = radius;
for (y = 0; y < h; y++) {
rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
for (i = -radius; i <= radius; i++) {
p = pix[yi + Math.min(wm, Math.max(i, 0))];
sir = stack[i + radius];
sir[0] = (p & 0xff0000) >> 16;
sir[1] = (p & 0x00ff00) >> 8;
sir[2] = (p & 0x0000ff);
rbs = r1 - Math.abs(i);
rsum += sir[0] * rbs;
gsum += sir[1] * rbs;
bsum += sir[2] * rbs;
if (i > 0) {
rinsum += sir[0];
ginsum += sir[1];
binsum += sir[2];
} else {
routsum += sir[0];
goutsum += sir[1];
boutsum += sir[2];
}
}
stackpointer = radius;
for (x = 0; x < w; x++) {
r[yi] = dv[rsum];
g[yi] = dv[gsum];
b[yi] = dv[bsum];
rsum -= routsum;
gsum -= goutsum;
bsum -= boutsum;
stackstart = stackpointer - radius + div;
sir = stack[stackstart % div];
routsum -= sir[0];
goutsum -= sir[1];
boutsum -= sir[2];
if (y == 0) {
vmin[x] = Math.min(x + radius + 1, wm);
}
p = pix[yw + vmin[x]];
sir[0] = (p & 0xff0000) >> 16;
sir[1] = (p & 0x00ff00) >> 8;
sir[2] = (p & 0x0000ff);
rinsum += sir[0];
ginsum += sir[1];
binsum += sir[2];
rsum += rinsum;
gsum += ginsum;
bsum += binsum;
stackpointer = (stackpointer + 1) % div;
sir = stack[(stackpointer) % div];
routsum += sir[0];
goutsum += sir[1];
boutsum += sir[2];
rinsum -= sir[0];
ginsum -= sir[1];
binsum -= sir[2];
yi++;
}
yw += w;
}
radius = originRadius;
for (x = 0; x < w; x++) {
rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
yp = -radius * w;
for (i = -radius; i <= radius; i++) {
yi = Math.max(0, yp) + x;
sir = stack[i + radius];
sir[0] = r[yi];
sir[1] = g[yi];
sir[2] = b[yi];
rbs = r1 - Math.abs(i);
rsum += r[yi] * rbs;
gsum += g[yi] * rbs;
bsum += b[yi] * rbs;
if (i > 0) {
rinsum += sir[0];
ginsum += sir[1];
binsum += sir[2];
} else {
routsum += sir[0];
goutsum += sir[1];
boutsum += sir[2];
}
if (i < hm) {
yp += w;
}
}
yi = x;
stackpointer = radius;
for (y = 0; y < h; y++) {
pix[yi] = 0xff000000 | (dv[rsum] << 16) | (dv[gsum] << 8)
| dv[bsum];
rsum -= routsum;
gsum -= goutsum;
bsum -= boutsum;
stackstart = stackpointer - radius + div;
sir = stack[stackstart % div];
routsum -= sir[0];
goutsum -= sir[1];
boutsum -= sir[2];
if (x == 0) {
vmin[y] = Math.min(y + r1, hm) * w;
}
p = x + vmin[y];
sir[0] = r[p];
sir[1] = g[p];
sir[2] = b[p];
rinsum += sir[0];
ginsum += sir[1];
binsum += sir[2];
rsum += rinsum;
gsum += ginsum;
bsum += binsum;
stackpointer = (stackpointer + 1) % div;
sir = stack[stackpointer];
routsum += sir[0];
goutsum += sir[1];
boutsum += sir[2];
rinsum -= sir[0];
ginsum -= sir[1];
binsum -= sir[2];
yi += w;
}
}
bitmap.setPixels(pix, 0, w, fromX, fromY, w, h);
return (bitmap);
}
Try to scale down the image 2, 4, 8, ... times and then scale it up again. That is fast. Otherwise implement it in renderscript.
If you want more than the scaling you can look at this code snippet in renderscript. It does the same kind of bluring as given in another answer. The same algorithm can be implemented in Java and is an optimization of the other answer. This code blurs one line. To blur a bitmap you should invoke this for all lines and then the same for all columns (you need to reimplement it to handle columns). To get a quick blur just do this once. If you want a better looking blur do it several times. I usually only do it twice.
The reason for doing one line is that I tried to parallelize the algorithm, that gave some improvement and is really simple in renderscript. I invoked the below code for all lines in parallel, and then the same for all columns.
int W = 8;
uchar4 *in;
uchar4 *out;
int N;
float invN;
uint32_t nx;
uint32_t ny;
void init_calc() {
N = 2*W+1;
invN = 1.0f/N;
nx = rsAllocationGetDimX(rsGetAllocation(in));
ny = rsAllocationGetDimY(rsGetAllocation(in));
}
void root(const ushort *v_in) {
float4 sum = 0;
uchar4 *head = in + *v_in * nx;
uchar4 *tail = head;
uchar4 *p = out + *v_in * nx;
uchar4 *hpw = head + W;
uchar4 *hpn = head + N;
uchar4 *hpx = head + nx;
uchar4 *hpxmw = head + nx - W - 1;
while (head < hpw) {
sum += rsUnpackColor8888(*head++);
}
while (head < hpn) {
sum += rsUnpackColor8888(*head++);
*p++ = rsPackColorTo8888(sum*invN);
}
while (head < hpx) {
sum += rsUnpackColor8888(*head++);
sum -= rsUnpackColor8888(*tail++);
*p++ = rsPackColorTo8888(sum*invN);
}
while (tail < hpxmw) {
sum -= rsUnpackColor8888(*tail++);
*p++ = rsPackColorTo8888(sum*invN);
}
}
Here is for the vertical bluring:
int W = 8;
uchar4 *in;
uchar4 *out;
int N;
float invN;
uint32_t nx;
uint32_t ny;
void init_calc() {
N = 2*W+1;
invN = 1.0f/N;
nx = rsAllocationGetDimX(rsGetAllocation(in));
ny = rsAllocationGetDimY(rsGetAllocation(in));
}
void root(const ushort *v_in) {
float4 sum = 0;
uchar4 *head = in + *v_in;
uchar4 *tail = head;
uchar4 *hpw = head + nx*W;
uchar4 *hpn = head + nx*N;
uchar4 *hpy = head + nx*ny;
uchar4 *hpymw = head + nx*(ny-W-1);
uchar4 *p = out + *v_in;
while (head < hpw) {
sum += rsUnpackColor8888(*head);
head += nx;
}
while (head < hpn) {
sum += rsUnpackColor8888(*head);
*p = rsPackColorTo8888(sum*invN);
head += nx;
p += nx;
}
while (head < hpy) {
sum += rsUnpackColor8888(*head);
sum -= rsUnpackColor8888(*tail);
*p = rsPackColorTo8888(sum*invN);
head += nx;
tail += nx;
p += nx;
}
while (tail < hpymw) {
sum -= rsUnpackColor8888(*tail);
*p = rsPackColorTo8888(sum*invN);
tail += nx;
p += nx;
}
}
And here is the Java code that calls into the rs code:
private RenderScript mRS;
private ScriptC_horzblur mHorizontalScript;
private ScriptC_vertblur mVerticalScript;
private ScriptC_blur mBlurScript;
private Allocation alloc1;
private Allocation alloc2;
private void hblur(int radius, Allocation index, Allocation in, Allocation out) {
mHorizontalScript.set_W(radius);
mHorizontalScript.bind_in(in);
mHorizontalScript.bind_out(out);
mHorizontalScript.invoke_init_calc();
mHorizontalScript.forEach_root(index);
}
private void vblur(int radius, Allocation index, Allocation in, Allocation out) {
mHorizontalScript.set_W(radius);
mVerticalScript.bind_in(in);
mVerticalScript.bind_out(out);
mVerticalScript.invoke_init_calc();
mVerticalScript.forEach_root(index);
}
Bitmap blur(Bitmap org, int radius) {
Bitmap out = Bitmap.createBitmap(org.getWidth(), org.getHeight(), org.getConfig());
blur(org, out, radius);
return out;
}
private Allocation createIndex(int size) {
Element element = Element.U16(mRS);
Allocation allocation = Allocation.createSized(mRS, element, size);
short[] rows = new short[size];
for (int i = 0; i < rows.length; i++) rows[i] = (short)i;
allocation.copyFrom(rows);
return allocation;
}
private void blur(Bitmap src, Bitmap dst, int r) {
Allocation alloc1 = Allocation.createFromBitmap(mRS, src);
Allocation alloc2 = Allocation.createTyped(mRS, alloc1.getType());
Allocation hIndexAllocation = createIndex(alloc1.getType().getY());
Allocation vIndexAllocation = createIndex(alloc1.getType().getX());
// Iteration 1
hblur(r, hIndexAllocation, alloc1, alloc2);
vblur(r, vIndexAllocation, alloc2, alloc1);
// Iteration 2
hblur(r, hIndexAllocation, alloc1, alloc2);
vblur(r, vIndexAllocation, alloc2, alloc1);
// Add more iterations if you like or simply make a loop
alloc1.copyTo(dst);
}
Gaussian blur is expensive to do accurately. A much faster approximation can be done by just iteratively averaging the pixels. It's still expensive to blur the image a lot but you can redraw between each iteration to at least give instant feedback and a nice animation of the image blurring.
static void blurfast(Bitmap bmp, int radius) {
int w = bmp.getWidth();
int h = bmp.getHeight();
int[] pix = new int[w * h];
bmp.getPixels(pix, 0, w, 0, 0, w, h);
for(int r = radius; r >= 1; r /= 2) {
for(int i = r; i < h - r; i++) {
for(int j = r; j < w - r; j++) {
int tl = pix[(i - r) * w + j - r];
int tr = pix[(i - r) * w + j + r];
int tc = pix[(i - r) * w + j];
int bl = pix[(i + r) * w + j - r];
int br = pix[(i + r) * w + j + r];
int bc = pix[(i + r) * w + j];
int cl = pix[i * w + j - r];
int cr = pix[i * w + j + r];
pix[(i * w) + j] = 0xFF000000 |
(((tl & 0xFF) + (tr & 0xFF) + (tc & 0xFF) + (bl & 0xFF) + (br & 0xFF) + (bc & 0xFF) + (cl & 0xFF) + (cr & 0xFF)) >> 3) & 0xFF |
(((tl & 0xFF00) + (tr & 0xFF00) + (tc & 0xFF00) + (bl & 0xFF00) + (br & 0xFF00) + (bc & 0xFF00) + (cl & 0xFF00) + (cr & 0xFF00)) >> 3) & 0xFF00 |
(((tl & 0xFF0000) + (tr & 0xFF0000) + (tc & 0xFF0000) + (bl & 0xFF0000) + (br & 0xFF0000) + (bc & 0xFF0000) + (cl & 0xFF0000) + (cr & 0xFF0000)) >> 3) & 0xFF0000;
}
}
}
bmp.setPixels(pix, 0, w, 0, 0, w, h);
}