I am unable to successfully convert a javafx.scene.image.Image to a org.opencv.core.Mat. The resulting matrix produces a black image. I've not used PixelReader before so I am unsure wether or not I am using it correctly.
Here is my code:
public static Mat imageToMat(Image image) {
int width = (int) image.getWidth();
int height = (int) image.getHeight();
byte[] buffer = new byte[width * height * 3];
PixelReader reader = image.getPixelReader();
WritablePixelFormat format = WritablePixelFormat.getByteBgraInstance();
reader.getPixels(0, 0, width, height, format, buffer, 0, 0);
Mat mat = new Mat(height, width, CvType.CV_8UC3);
mat.put(0, 0, buffer);
return mat;
}
Any help/solutions would be greatly appreciated! :) Thank you.
That stuff is still circumstantial. I've found 2 working solutions. I'll just post my OpenCvUtils class, hope it helps until someone comes up with a better solution:
import java.awt.AlphaComposite;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.io.ByteArrayInputStream;
import java.net.URISyntaxException;
import java.nio.file.Paths;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.image.Image;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.MatOfByte;
import org.opencv.imgcodecs.Imgcodecs;
public class OpenCvUtils {
/**
* Convert a Mat object (OpenCV) in the corresponding Image for JavaFX
*
* #param frame
* the {#link Mat} representing the current frame
* #return the {#link Image} to show
*/
public static Image mat2Image(Mat frame) {
// create a temporary buffer
MatOfByte buffer = new MatOfByte();
// encode the frame in the buffer, according to the PNG format
Imgcodecs.imencode(".png", frame, buffer);
// build and return an Image created from the image encoded in the
// buffer
return new Image(new ByteArrayInputStream(buffer.toArray()));
}
public static Mat image2Mat( Image image) {
BufferedImage bImage = SwingFXUtils.fromFXImage(image, null);
return bufferedImage2Mat( bImage);
}
// http://www.codeproject.com/Tips/752511/How-to-Convert-Mat-to-BufferedImage-Vice-Versa
public static Mat bufferedImage2Mat(BufferedImage in)
{
Mat out;
byte[] data;
int r, g, b;
int height = in.getHeight();
int width = in.getWidth();
if(in.getType() == BufferedImage.TYPE_INT_RGB || in.getType() == BufferedImage.TYPE_INT_ARGB)
{
out = new Mat(height, width, CvType.CV_8UC3);
data = new byte[height * width * (int)out.elemSize()];
int[] dataBuff = in.getRGB(0, 0, width, height, null, 0, width);
for(int i = 0; i < dataBuff.length; i++)
{
data[i*3 + 2] = (byte) ((dataBuff[i] >> 16) & 0xFF);
data[i*3 + 1] = (byte) ((dataBuff[i] >> 8) & 0xFF);
data[i*3] = (byte) ((dataBuff[i] >> 0) & 0xFF);
}
}
else
{
out = new Mat(height, width, CvType.CV_8UC1);
data = new byte[height * width * (int)out.elemSize()];
int[] dataBuff = in.getRGB(0, 0, width, height, null, 0, width);
for(int i = 0; i < dataBuff.length; i++)
{
r = (byte) ((dataBuff[i] >> 16) & 0xFF);
g = (byte) ((dataBuff[i] >> 8) & 0xFF);
b = (byte) ((dataBuff[i] >> 0) & 0xFF);
data[i] = (byte)((0.21 * r) + (0.71 * g) + (0.07 * b)); //luminosity
}
}
out.put(0, 0, data);
return out;
}
public static String getOpenCvResource(Class<?> clazz, String path) {
try {
return Paths.get( clazz.getResource(path).toURI()).toString();
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
}
// Convert image to Mat
// alternate version http://stackoverflow.com/questions/21740729/converting-bufferedimage-to-mat-opencv-in-java
public static Mat bufferedImage2Mat_v2(BufferedImage im) {
im = toBufferedImageOfType(im, BufferedImage.TYPE_3BYTE_BGR);
// Convert INT to BYTE
//im = new BufferedImage(im.getWidth(), im.getHeight(),BufferedImage.TYPE_3BYTE_BGR);
// Convert bufferedimage to byte array
byte[] pixels = ((DataBufferByte) im.getRaster().getDataBuffer()).getData();
// Create a Matrix the same size of image
Mat image = new Mat(im.getHeight(), im.getWidth(), CvType.CV_8UC3);
// Fill Matrix with image values
image.put(0, 0, pixels);
return image;
}
private static BufferedImage toBufferedImageOfType(BufferedImage original, int type) {
if (original == null) {
throw new IllegalArgumentException("original == null");
}
// Don't convert if it already has correct type
if (original.getType() == type) {
return original;
}
// Create a buffered image
BufferedImage image = new BufferedImage(original.getWidth(), original.getHeight(), type);
// Draw the image onto the new buffer
Graphics2D g = image.createGraphics();
try {
g.setComposite(AlphaComposite.Src);
g.drawImage(original, 0, 0, null);
}
finally {
g.dispose();
}
return image;
}
}
Thanks to Nikos Paraskevopoulos for suggesting setting the scanlineStride parameter of the PixelReader::getPixels() method, this has solved it. :)
Working code below:
public static Mat imageToMat(Image image) {
int width = (int) image.getWidth();
int height = (int) image.getHeight();
byte[] buffer = new byte[width * height * 4];
PixelReader reader = image.getPixelReader();
WritablePixelFormat<ByteBuffer> format = WritablePixelFormat.getByteBgraInstance();
reader.getPixels(0, 0, width, height, format, buffer, 0, width * 4);
Mat mat = new Mat(height, width, CvType.CV_8UC4);
mat.put(0, 0, buffer);
return mat;
}
You need convert : Mat > BufferedImage > FXImage
private Image mat2Image(Mat src)
{
BufferedImage image = ImageConverter.toImage(src);
return SwingFXUtils.toFXImage(image, null);
}
Class:
public class ImageConverter {
/**
* Converts/writes a Mat into a BufferedImage.
*
* #param src Mat of type CV_8UC3 or CV_8UC1
* #return BufferedImage of type TYPE_3BYTE_BGR or TYPE_BYTE_GRAY
*/
public static BufferedImage toImage(Mat src)
{
if ( src != null ) {
int cols = src.cols();
int rows = src.rows();
int elemSize = (int)src.elemSize();
byte[] data = new byte[cols * rows * elemSize];
int type;
src.data().get(data);
switch (src.channels()) {
case 1:
type = BufferedImage.TYPE_BYTE_GRAY;
break;
case 3:
type = BufferedImage.TYPE_3BYTE_BGR;
// bgr to rgb
byte b;
for(int i=0; i<data.length; i=i+3) {
b = data[i];
data[i] = data[i+2];
data[i+2] = b;
}
break;
default:
return null;
}
BufferedImage bimg = new BufferedImage(cols, rows, type);
bimg.getRaster().setDataElements(0, 0, cols, rows, data);
return bimg;
}
return null;
}
}
Following the solution above it may be also necessary to convert the format from four bytes (CvType.CV_8UC4) to three bytes (CvType.CV_8UC3) depending on what you are finally seeking. For example, if I read a xx.jpa image, it is RGB format.
if (isRGB)
Imgproc.cvtColor(mat,mat,Imgproc.COLOR_RGBA2RGB);
//or...COLOR_BGR2RGB,COLOR_BGRA2RGB,COLOR_BGR2BGRA
Related
How do I flip an Screenshot image? I can't find my problem anywhere else.Example code:
/*
*#param fileLoc //Location of fileoutput destination
*#param format //"png"
*#param WIDTH //Display.width();
*#param HEIGHT //Display.height();
*/
private void getScreenImage(){
int[] pixels = new int[WIDTH * HEIGHT];
int bindex;
// allocate space for RBG pixels
ByteBuffer fb = ByteBuffer.allocateDirect(WIDTH * HEIGHT * 3);//.order(ByteOrder.nativeOrder());
// grab a copy of the current frame contents as RGB
glReadPixels(0, 0, WIDTH, HEIGHT, GL_RGB, GL_UNSIGNED_BYTE, fb);
BufferedImage image = new BufferedImage(WIDTH, HEIGHT,BufferedImage.TYPE_INT_RGB);
// convert RGB data in ByteBuffer to integer array
for (int i=0; i < pixels.length; i++) {
bindex = i * 3;
pixels[i] =
((fb.get(bindex) << 16)) +
((fb.get(bindex+1) << 8)) +
((fb.get(bindex+2) << 0));
}
try {
//Create a BufferedImage with the RGB pixels then save as PNG
image.setRGB(0, 0, WIDTH, HEIGHT, pixels, 0 , WIDTH);
ImageIO.write(image, format , fileLoc);
}
catch (Exception e) {
System.out.println("ScreenShot() exception: " +e);
}
}
Basically the code works for capturing the screen and storing at as "png" format.
But it output's the image horizontally flipped, because glReadPixels();,
read from bottom-left to top-right.
So how do I flip the image horizontally before I ImageIO.write();?
Thanks in-front,
Rose.
E.G. of flipping an image horizontally using an AffineTransform.
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class Test001 {
public static BufferedImage getFlippedImage(BufferedImage bi) {
BufferedImage flipped = new BufferedImage(
bi.getWidth(),
bi.getHeight(),
bi.getType());
AffineTransform tran = AffineTransform.getTranslateInstance(bi.getWidth(), 0);
AffineTransform flip = AffineTransform.getScaleInstance(-1d, 1d);
tran.concatenate(flip);
Graphics2D g = flipped.createGraphics();
g.setTransform(tran);
g.drawImage(bi, 0, 0, null);
g.dispose();
return flipped;
}
Test001(BufferedImage bi) {
JPanel gui = new JPanel(new GridLayout(1,2,2,2));
gui.add(new JLabel(new ImageIcon(bi)));
gui.add(new JLabel(new ImageIcon(getFlippedImage(bi))));
JOptionPane.showMessageDialog(null, gui);
}
public static void main(String[] args) throws AWTException {
final Robot robot = new Robot();
Runnable r = new Runnable() {
#Override
public void run() {
final BufferedImage bi = robot.createScreenCapture(
new Rectangle(0, 360, 200, 100));
new Test001(bi);
}
};
SwingUtilities.invokeLater(r);
}
}
It's worth noting that it might be faster to simply read the pixels out of the buffer in the order you want them, rather than read them backwards and do a costly transform operation. Additionally, since you know for sure that the BufferedImage is TYPE_INT_RGB it should be safe to write directly into its raster.
ByteBuffer fb = BufferUtils.createByteBuffer(WIDTH * HEIGHT * 3);
BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
glReadPixels(0, 0, WIDTH, HEIGHT, GL_RGB, GL_UNSIGNED_BYTE, fb);
int[] pixels = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
for (int i = pixels.length - 1; i >= 0; i--) {
int x = i % WIDTH, y = i / WIDTH * WIDTH;
pixels[y + WIDTH - 1 - x] = (fb.get() & 0xff) << 16 | (fb.get() & 0xff) << 8 | fb.get() & 0xff;
}
I have a byte array containing pixel values from a .bmp file. It was generated by doing this:
BufferedImage readImage = ImageIO.read(new File(fileName));
byte imageData[] = ((DataBufferByte)readImage.getData().getDataBuffer()).getData();
Now I need to recreate the .bmp image. I tried to make a BufferedImage and set the pixels of the WritableRaster by calling the setPixels method. But there I have to provide an int[], float[] or double[] array. Maybe I need to convert the byte array into one of these. But I don't know how to do that. I also tried the setDataElements method. But I am not sure how to use this method either.
Can anyone explain how to create a bmp image from a byte array?
Edit: #Perception
This is what I have done so far:
private byte[] getPixelArrayToBmpByteArray(byte[] pixelData, int width, int height, int depth) throws Exception{
int[] pixels = byteToInt(pixelData);
BufferedImage image = null;
if(depth == 8) {
image = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);
}
else if(depth == 24){
image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
}
WritableRaster raster = (WritableRaster) image.getData();
raster.setPixels(0, 0, width, height, pixels);
image.setData(raster);
return getBufferedImageToBmpByteArray(image);
}
private byte[] getBufferedImageToBmpByteArray(BufferedImage image) {
byte[] imageData = null;
try {
ByteArrayOutputStream bas = new ByteArrayOutputStream();
ImageIO.write(image, "bmp", bas);
imageData = bas.toByteArray();
bas.close();
} catch (Exception e) {
e.printStackTrace();
}
return imageData;
}
private int[] byteToInt(byte[] data) {
int[] ints = new int[data.length];
for (int i = 0; i
You need to pack three bytes into each integer you make. Depending on the format of the buffered image, this will be 0xRRGGBB.
byteToInt will have to consume three bytes like this:
private int[] byteToInt(byte[] data) {
int[] ints = new int[data.length / 3];
int byteIdx = 0;
for (int pixel = 0; pixel < ints.length) {
int rByte = (int) pixels[byteIdx++] & 0xFF;
int gByte = (int) pixels[byteIdx++] & 0xFF;
int bByte = (int) pixels[byteIdx++] & 0xFF;
int rgb = (rByte << 16) | (gByte << 8) | bByte
ints[pixel] = rgb;
}
}
You can also use ByteBuffer.wrap(arr, offset, length).toInt()
Having just a byte array is not enough. You also need to construct a header (if you are reading from a raw format, such as inside a DICOM file).
Does anyone have an idea, link, library, source code, ... on how to convert photo's and images (bitmaps) to sketchy-like pictures? I can't find any good sources on how to do it.
I found this link How to cartoon-ify an image programmatically? about how to cartoon-ify a image programmatically, but i prefer to make it image-to-sketch one.
I want to make an android app that can programmatically "convert" JPEG photo's to sketchy images.
Ok, so i found my own answer using different techniques like Mark told me.
I use the following pseudocode:
*s = Read-File-Into-Image("/path/to/image")
*g = Convert-To-Gray-Scale(s)
*i = Invert-Colors(g)
*b = Apply-Gaussian-Blur(i)
*result = Color-Dodge-Blend-Merge(b,g)
The first four methods were easily to find on the internet, however on the last one I couldn't find a lot of information, not even source code. So I searched on how PS did it and found the following formula in c++:
((uint8)((B == 255) ? B:min(255, ((A << 8 ) / (255 - B)))))
Then i converted it to Java with the following code:
private int colordodge(int in1, int in2) {
float image = (float)in2;
float mask = (float)in1;
return ((int) ((image == 255) ? image:Math.min(255, (((long)mask << 8 ) / (255 - image)))));
}
/**
* Blends 2 bitmaps to one and adds the color dodge blend mode to it.
*/
public Bitmap ColorDodgeBlend(Bitmap source, Bitmap layer) {
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);
buffOut.put(pixel);
}
buffOut.rewind();
base.copyPixelsFromBuffer(buffOut);
blend.recycle();
return base;
}
If the code could be improved, please post a new answer or comment below. Thanks!
And adding color.
*s = Read-File-Into-Image("/path/to/image")
*g = Convert-To-Gray-Scale(s)
*i = Invert-Colors(g)
*b = Apply-Gaussian-Blur(i)
*result = Color-Dodge-Blend-Merge(b,g)
*s2 = Apply-Gaussian-Blur(s) //I use radius 3
*cartoon = Apply-Color(s2, result)
I little modification to ColorDodgeBlend to eliminate all colors.
public Bitmap ColorDodgeBlend(Bitmap source, Bitmap layer)
....
//before buffOut.put(pixel);
float[] hsv = new float[3];
Color.colorToHSV(pixel, hsv);
hsv[1] = 0.0f;
float top = VALUE_TOP; //Between 0.0f .. 1.0f I use 0.87f
if (hsv[2] <= top) {
hsv[2] = 0.0f;
} else {
hsv[2] = 1.0f;
}
pixel = Color.HSVToColor(hsv);
An the applying color method:
//hue, saturarion, value intervals size are for reduce colors on Bitmap
//saturation, value percents are for increment or decrement [0..100..)
public Bitmap getCartoonizedBitmap(Bitmap realBitmap, Bitmap dodgeBlendBitmap, int hueIntervalSize, int saturationIntervalSize, int valueIntervalSize, int saturationPercent, int valuePercent) {
// Bitmap bitmap = Bitmap.createBitmap(scaledBitmap);
// //fastblur(scaledBitmap, 4);
Bitmap base = fastblur(realBitmap, 3).copy(Config.ARGB_8888, true);
Bitmap dodge = dodgeBlendBitmap.copy(Config.ARGB_8888, false);
try {
int realColor;
int color;
float top = VALUE_TOP; //Between 0.0f .. 1.0f I use 0.87f
IntBuffer templatePixels = IntBuffer.allocate(dodge.getWidth()
* dodge.getHeight());
IntBuffer scaledPixels = IntBuffer.allocate(base.getWidth()
* base.getHeight());
IntBuffer buffOut = IntBuffer.allocate(base.getWidth()
* base.getHeight());
base.copyPixelsToBuffer(scaledPixels);
dodge.copyPixelsToBuffer(templatePixels);
templatePixels.rewind();
scaledPixels.rewind();
buffOut.rewind();
while (buffOut.position() < buffOut.limit()) {
color = (templatePixels.get());
realColor = scaledPixels.get();
float[] realHSV = new float[3];
Color.colorToHSV(realColor, realHSV);
realHSV[0] = getRoundedValue(realHSV[0], hueIntervalSize);
realHSV[2] = (getRoundedValue(realHSV[2] * 100,
valueIntervalSize) / 100) * (valuePercent / 100);
realHSV[2] = realHSV[2]<1.0?realHSV[2]:1.0f;
realHSV[1] = realHSV[1] * (saturationPercent / 100);
realHSV[1] = realHSV[1]<1.0?realHSV[1]:1.0f;
float[] HSV = new float[3];
Color.colorToHSV(color, HSV);
boolean putBlackPixel = HSV[2] <= top;
realColor = Color.HSVToColor(realHSV);
if (putBlackPixel) {
buffOut.put(color);
} else {
buffOut.put(realColor);
}
}// END WHILE
dodge.recycle();
buffOut.rewind();
base.copyPixelsFromBuffer(buffOut);
} catch (Exception e) {
// TODO: handle exception
}
return base;
}
public static float getRoundedValue(float value, int intervalSize) {
float result = Math.round(value);
int mod = ((int) result) % intervalSize;
result += mod < (intervalSize / 2) ? -mod : intervalSize - mod;
return result;
}
This is not improved.
Its better if Apply-Color and Color-Dodge-Blend-Merge merges.
Thanks to XverhelstX for his Question-Answer
Here's an example of how to create such an effect in a graphics editing program:
http://www.createblog.com/paintshop-pro-tutorials/14018-sketch-effect/
Convert the image to grayscale.
Make a copy and invert the intensities.
Blur the copy.
Combine the two images using a Color Dodge formula.
Here is the clear answer with the code according to #XverhelstX I have created a code to get clearly sketch from photo.
Take Image from source and convert it into an Input Bitmap. Now call the method below and pass Bitmap into it.
public Bitmap Changetosketch(Bitmap bmp){
Bitmap Copy,Invert,Result;
Copy =bmp;
Copy = toGrayscale(Copy);
Invert = createInvertedBitmap(Copy);
Invert = Blur.blur(MainActivity.this, Invert);
Result = ColorDodgeBlend(Invert, Copy);
return Result;
}
Here we got 3 methods GrayScale,Inverted,and Color-DodgeBlend.
public static Bitmap toGrayscale(Bitmap bmpOriginal)
{
int width, height;
height = bmpOriginal.getHeight();
width = bmpOriginal.getWidth();
Bitmap bmpGrayscale = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
Canvas c = new Canvas(bmpGrayscale);
Paint paint = new Paint();
ColorMatrix cm = new ColorMatrix();
cm.setSaturation(0);
ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm);
paint.setColorFilter(f);
c.drawBitmap(bmpOriginal, 0, 0, paint);
return bmpGrayscale;
}
public static Bitmap createInvertedBitmap(Bitmap src) {
ColorMatrix colorMatrix_Inverted =
new ColorMatrix(new float[] {
-1, 0, 0, 0, 255,
0, -1, 0, 0, 255,
0, 0, -1, 0, 255,
0, 0, 0, 1, 0});
ColorFilter ColorFilter_Sepia = new ColorMatrixColorFilter(
colorMatrix_Inverted);
Bitmap bitmap = Bitmap.createBitmap(src.getWidth(), src.getHeight(),
Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint();
paint.setColorFilter(ColorFilter_Sepia);
canvas.drawBitmap(src, 0, 0, paint);
return bitmap;
}
public Bitmap ColorDodgeBlend(Bitmap source, Bitmap layer) {
Bitmap base = source.copy(Bitmap.Config.ARGB_8888, true);
Bitmap blend = layer.copy(Bitmap.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);
buffOut.put(pixel);
}
buffOut.rewind();
base.copyPixelsFromBuffer(buffOut);
blend.recycle();
return base;
}
private int colordodge(int in1, int in2) {
float image = (float)in2;
float mask = (float)in1;
return ((int) ((image == 255) ? image:Math.min(255, (((long)mask << 8 ) / (255 - image)))));
}
One thing to be noted that in my code I am blurring the bitmap using Renderscript.
Here is the Blur class.
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.support.v8.renderscript.Allocation;
import android.support.v8.renderscript.Element;
import android.support.v8.renderscript.RenderScript;
import android.support.v8.renderscript.ScriptIntrinsicBlur;
import android.view.View;
public class Blur {
private static final float BITMAP_SCALE = 0.4f;
private static final float BLUR_RADIUS = 4.5f;
public static Bitmap blur(View v) {
return blur(v.getContext(), getScreenshot(v));
}
public static Bitmap blur(Context ctx, Bitmap image) {
Bitmap photo = image.copy(Bitmap.Config.ARGB_8888, true);
try {
final RenderScript rs = RenderScript.create( ctx );
final Allocation input = Allocation.createFromBitmap(rs, photo, Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
final Allocation output = Allocation.createTyped(rs, input.getType());
final ScriptIntrinsicBlur script = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
script.setRadius( BLUR_RADIUS ); /* e.g. 3.f */
script.setInput( input );
script.forEach( output );
output.copyTo( photo );
}catch (Exception e){
e.printStackTrace();
}
return photo;
}
private static Bitmap getScreenshot(View v) {
Bitmap b = Bitmap.createBitmap(v.getWidth(), v.getHeight(), Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(b);
v.draw(c);
return b;
}
}
After setting all this, simply pass your input bitmap into the first method from onCreate method i-e:
Done.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
ResultBitmap = ChangetoSketch(InputBitmap);
ImageView.setImageBitmap(ResultBitmap);
}
});
Ok if you got one then you can post the code here and see if someone can help you translate the code to java ..the other alternative being..you may have to use the ndk perhaps..However I did find some links and I am posting them here..hope you find something interesting here in these links
How to cartoon-ify an image programmatically? you can check this link
I am trying to resized a bufferedimage. I am able to store it and show up on a jframe no problems but I can't seem to resize it. Any tips on how I can change this to make it work and show the image as a 200*200 file would be great
private void profPic(){
String path = factory.getString("bottle");
BufferedImage img = ImageIO.read(new File(path));
}
public static BufferedImage resize(BufferedImage img, int newW, int newH) {
int w = img.getWidth();
int h = img.getHeight();
BufferedImage dimg = new BufferedImage(newW, newH, img.getType());
Graphics2D g = dimg.createGraphics();
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.drawImage(img, 0, 0, newW, newH, 0, 0, w, h, null);
g.dispose();
return dimg;
}
Updated answer
I cannot recall why my original answer worked but having tested it in a separate environment, I agree, the original accepted answer doesn't work (why I said it did I cannot remember either). This, on the other hand, did work:
public static BufferedImage resize(BufferedImage img, int newW, int newH) {
Image tmp = img.getScaledInstance(newW, newH, Image.SCALE_SMOOTH);
BufferedImage dimg = new BufferedImage(newW, newH, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = dimg.createGraphics();
g2d.drawImage(tmp, 0, 0, null);
g2d.dispose();
return dimg;
}
If all that is required is to resize a BufferedImage in the resize method, then the Thumbnailator library can do that fairly easily:
public static BufferedImage resize(BufferedImage img, int newW, int newH) {
return Thumbnails.of(img).size(newW, newH).asBufferedImage();
}
The above code will resize the img to fit the dimensions of newW and newH while maintaining the aspect ratio of the original image.
If maintaining the aspect ratio is not required and resizing to exactly the given dimensions is required, then the forceSize method can be used in place of the size method:
public static BufferedImage resize(BufferedImage img, int newW, int newH) {
return Thumbnails.of(img).forceSize(newW, newH).asBufferedImage();
}
Using the Image.getScaledInstance method will not guarantee that the aspect ratio of the original image will be maintained for the resized image, and furthermore, it is in general very slow.
Thumbnailator uses a technique to progressively resize the image which can be several times faster than Image.getScaledInstance while achieving an image quality which generally is comparable.
Disclaimer: I am the maintainer of this library.
Here's some code that I have used to resize bufferedimages, no frills, pretty quick:
public static BufferedImage scale(BufferedImage src, int w, int h)
{
BufferedImage img =
new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
int x, y;
int ww = src.getWidth();
int hh = src.getHeight();
int[] ys = new int[h];
for (y = 0; y < h; y++)
ys[y] = y * hh / h;
for (x = 0; x < w; x++) {
int newX = x * ww / w;
for (y = 0; y < h; y++) {
int col = src.getRGB(newX, ys[y]);
img.setRGB(x, y, col);
}
}
return img;
}
This class resize from a file and get the format name:
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.ImageWriter;
import javax.imageio.stream.ImageInputStream;
import org.apache.commons.io.IOUtils;
public class ImageResizer {
public static void main(String as[]) throws IOException{
File f = new File("C:/Users/samsungrob/Desktop/shuttle.jpg");
byte[] ba = resize(f, 600, 600);
IOUtils.write(ba, new FileOutputStream( new File("C:/Users/samsungrob/Desktop/shuttle_resized.jpg") ) );
}
public static byte[] resize(File file,
int maxWidth, int maxHeight) throws IOException{
int scaledWidth = 0, scaledHeight = 0;
BufferedImage img = ImageIO.read((ImageInputStream) file );
scaledWidth = maxWidth;
scaledHeight = (int) (img.getHeight() * ( (double) scaledWidth / img.getWidth() ));
if (scaledHeight> maxHeight) {
scaledHeight = maxHeight;
scaledWidth= (int) (img.getWidth() * ( (double) scaledHeight/ img.getHeight() ));
if (scaledWidth > maxWidth) {
scaledWidth = maxWidth;
scaledHeight = maxHeight;
}
}
Image resized = img.getScaledInstance( scaledWidth, scaledHeight, Image.SCALE_SMOOTH);
BufferedImage buffered = new BufferedImage(scaledWidth, scaledHeight, Image.SCALE_REPLICATE);
buffered.getGraphics().drawImage(resized, 0, 0 , null);
String formatName = getFormatName( file ) ;
ByteArrayOutputStream out = new ByteArrayOutputStream();
ImageIO.write(buffered,
formatName,
out);
return out.toByteArray();
}
private static String getFormatName(ImageInputStream iis) {
try {
// Find all image readers that recognize the image format
Iterator iter = ImageIO.getImageReaders(iis);
if (!iter.hasNext()) {
// No readers found
return null;
}
// Use the first reader
ImageReader reader = (ImageReader)iter.next();
// Close stream
iis.close();
// Return the format name
return reader.getFormatName();
} catch (IOException e) {
}
return null;
}
private static String getFormatName(File file) throws IOException {
return getFormatName( ImageIO.createImageInputStream(file) );
}
private static String getFormatName(InputStream is) throws IOException {
return getFormatName( ImageIO.createImageInputStream(is) );
}
}
This is a shortened version of what is actually happening in imgscalr, if you just want to use the "balanced" smoothing:
/**
* Takes a BufferedImage and resizes it according to the provided targetSize
*
* #param src the source BufferedImage
* #param targetSize maximum height (if portrait) or width (if landscape)
* #return a resized version of the provided BufferedImage
*/
private BufferedImage resize(BufferedImage src, int targetSize) {
if (targetSize <= 0) {
return src; //this can't be resized
}
int targetWidth = targetSize;
int targetHeight = targetSize;
float ratio = ((float) src.getHeight() / (float) src.getWidth());
if (ratio <= 1) { //square or landscape-oriented image
targetHeight = (int) Math.ceil((float) targetWidth * ratio);
} else { //portrait image
targetWidth = Math.round((float) targetHeight / ratio);
}
BufferedImage bi = new BufferedImage(targetWidth, targetHeight, src.getTransparency() == Transparency.OPAQUE ? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = bi.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); //produces a balanced resizing (fast and decent quality)
g2d.drawImage(src, 0, 0, targetWidth, targetHeight, null);
g2d.dispose();
return bi;
}
try the imgscalr library. Best lib i found- very fast, good quality and simple to use
BufferedImage thumbnail = Scalr.resize(image, 150);
deprecated link: http://www.thebuzzmedia.com/software/imgscalr-java-image-scaling-library/
Apache 2 License
Check this out, it helps:
BufferedImage bImage = ImageIO.read(new File(C:\image.jpg);
BufferedImage thumbnail = Scalr.resize(bImage, Scalr.Method.SPEED, Scalr.Mode.FIT_TO_WIDTH,
750, 150, Scalr.OP_ANTIALIAS);
I'm trying to convert from RGB to GrayScale Image.
The method that does this task is the following:
public BufferedImage rgbToGrayscale(BufferedImage in)
{
int width = in.getWidth();
int height = in.getHeight();
BufferedImage grayImage = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);
WritableRaster raster = grayImage.getRaster();
int [] rgbArray = new int[width * height];
in.getRGB(0, 0, width, height, rgbArray, 0, width);
int [] outputArray = new int[width * height];
int red, green, blue, gray;
for(int i = 0; i < (height * width); i++)
{
red = (rgbArray[i] >> 16) & 0xff;
green = (rgbArray[i] >> 8) & 0xff;
blue = (rgbArray[i]) & 0xff;
gray = (int)( (0.30 * red) + (0.59 * green) + (0.11 * blue));
if(gray < 0)
gray = 0;
if(gray > 255)
gray = 255;
outputArray[i] = (gray & 0xff);
}
}
raster.setPixels(0, 0, width, height, outputArray);
return grayImage;
}
I have a method that saves the pixels value in a file:
public void writeImageValueToFile(BufferedImage in, String fileName)
{
int width = in.getWidth();
int height = in.getHeight();
try
{
FileWriter fstream = new FileWriter(fileName + ".txt");
BufferedWriter out = new BufferedWriter(fstream);
int [] grayArray = new int[width * height];
in.getRGB(0, 0, width, height, grayArray, 0, width);
for(int i = 0; i < (height * width); i++)
{
out.write((grayArray[i] & 0xff) + "\n");
}
out.close();
} catch (Exception e)
{
System.err.println("Error: " + e.getMessage());
}
}
The problem that I have is that, the RGB value I get from my method, is always bigger than the expected one.
I created an image and I filled it with color 128, 128, 128. According to the first method, if I print the outputArray's data, I get:
r, g, b = 128, 128, 128. Final = 127 ---> correct :D
However, when I called the second method, I got the RGB value 187 which is incorrect.
Any suggestion?
Thanks!!!
Take a look at javax.swing.GrayFilter, it uses the RBGImageFilter class to accomplish the same thing and has very similar implementation. It may make your life simpler.
I'm not an expert at these things but aren't RGB values stored as hex (base16)? If so, theproblem lies in your assumption that the operation & 0xff will cause your int to be stored/handled as base16. It is just a notation and default int usage in strings will always be base10.
int a = 200;
a = a & 0xff;
System.out.println(a);
// output
200
You need to use an explicit base16 toString() method.
System.out.println(Integer.toHexString(200));
// output
c8