I have array of byte for image , and I want to rotate image by this array ,
this is my code :
BufferedImage img = ImageUtil.load(inputImagePath);
WritableRaster raster = img .getRaster();
DataBufferByte data = (DataBufferByte) raster.getDataBuffer();
byte [] pixel = data.getData();
how i can do this ? ,
thanks
After some work, I came up with this:
public class ImageRotation {
public static void main(String[] args) throws IOException {
BufferedImage img = ImageIO.read(
ImageRotation.class
.getResourceAsStream("Capture.PNG"));
JPanel pane = new JPanel();
pane.setLayout(new BorderLayout());
pane.add(
new JLabel("Original", new ImageIcon(img), JLabel.CENTER),
BorderLayout.WEST);
pane.add(
new JLabel("Rotated", new ImageIcon(rotateClockwise(img)), JLabel.CENTER),
BorderLayout.EAST);
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(pane);
frame.setVisible(true);
frame.pack();
}
static BufferedImage rotateClockwise(BufferedImage img) {
int[] origPix = getIntBuff(img);
int newWidth = img.getHeight();
int newHeight = img.getWidth();
int[] buff = new int[newWidth * newHeight];
// formula for determining pixel mapping
// (sizeOf(old y) - 1) - old y -> new x
// old x -> new y
for (int x = 0; x < img.getWidth(); x++)
for (int y = 0; y < img.getHeight(); y++) {
int pix = origPix[x + (y * img.getWidth())];
int newX = img.getHeight() - 1 - y, newY = x;
buff[newX + (newWidth * newY)] = pix;
}
// we have now rotated the array clockwise, time to place the buffer in an image
int type = BufferedImage.TYPE_INT_ARGB;
BufferedImage ret = new BufferedImage(newWidth, newHeight, type);
WritableRaster wr = ret.getRaster();
wr.setDataElements(0, 0, newWidth, newHeight, buff);
return ret;
}
// variation of convertTo2DWithoutUsingGetRGB http://stackoverflow.com/a/9470843/4683264
private static int[] getIntBuff(BufferedImage image) {
final byte[] pixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
final int width = image.getWidth();
final int height = image.getHeight();
final boolean hasAlphaChannel = image.getAlphaRaster() != null;
int[] result = new int[height * width];
final int pixelLength = hasAlphaChannel ? 4 : 3;
for (int pixel = 0, resInd = 0; pixel < pixels.length; pixel += pixelLength) {
int argb = 0;
if (hasAlphaChannel)
argb += (((int) pixels[pixel] & 0xff) << 24); // alpha
else
argb += -16777216; // 255 alpha
argb += ((int) pixels[pixel + 1] & 0xff); // blue
argb += (((int) pixels[pixel + 2] & 0xff) << 8); // green
argb += (((int) pixels[pixel + 3] & 0xff) << 16); // red
result[resInd++] = argb;
}
return result;
}
}
Result:
Right now it only rotates the image clockwise, but once you find the pixel mappings from the old to new image for, say, counterclockwise, all you need to change is in the nested for loop in the rotateClockwise method to:
int newX = y, newY = img.getWidth() - 1 - x;
Related
I'm trying to convert an image from YUV to RGB inside onImageAvailable method in java.
I'm using openCV for conversion.
I can't use RGB format from android Camera2 for avoiding frame loss.
I can't chose the best format for conversion.
Image.Plane Y = image.getPlanes()[0];
Image.Plane U = image.getPlanes()[1];
Image.Plane V = image.getPlanes()[2];
Y.getBuffer().position(0);
U.getBuffer().position(0);
V.getBuffer().position(0);
int Yb = Y.getBuffer().remaining();
int Ub = U.getBuffer().remaining();
int Vb = V.getBuffer().remaining();
ByteBuffer buffer = ByteBuffer.allocateDirect( Yb + Ub + Vb);
buffer.put(Y.getBuffer());
buffer.put(U.getBuffer());
buffer.put(V.getBuffer());
// Image is 640 x 480
Mat yuvMat = new Mat(960, 640, CvType.CV_8UC1);
yuvMat.put(0, 0, buffer.array());
// I don't know what is the correct format
Mat rgbMat = new Mat(yuvMat.rows, yuvMat.cols, CvType.CV_8UC4);
Imgproc.cvtColor(yuvMat, rgbMat, Imgproc.COLOR_YUV420sp2RGBA);
final Bitmap bit = Bitmap.createBitmap(rgbMat.cols(), rgbMat.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(rgbMat, bit);
Actually, I obtain only cropped grayscale image
Try this function:
void decodeYUV420SP( byte[] 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);
int nIdx = ((width - i - 1) * height + height - j - 1) * 3;//device
//int nIdx = (i * height + j) * 3;//nox
rgb[nIdx] = (byte) (((r << 6) & 0xff0000)>>16);
rgb[nIdx+1] = (byte) (((g >> 2) & 0xff00)>>8);
rgb[nIdx+2] = (byte) ((b >> 10) & 0xff);
}
}
}
Use : decodeYUV420SP( rgb, camData, nWidth234, nHeight234 );
You can get RGB byte array;
If you need get the image from byte array, try this.
public boolean convertYunToJpeg(byte[] data, int width, int height){
YuvImage image = new YuvImage(data, ImageFormat.NV21, width, height, null);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int quailty = 20;
image.compressToJpeg(new Rect(0,0, width, height), quailty, baos);
byte[] jpegByteArray = baos.toByteArray();
Bitmap bitmap = BitmapFactory.decodeByteArray(jpegByteArray, 0, jpegByteArray.length);
Matrix matrix = new Matrix();
matrix.postRotate(-90);
Bitmap lastbitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
try {
File file = new File(BaseApplication.DIRECTORY + mCode + ".png");
if(!file.exists()){
RandomAccessFile me = new RandomAccessFile(BaseApplication.DIRECTORY + mCode + ".png", "rw");
me.writeInt(5);
me.close();
file = new File(BaseApplication.DIRECTORY + mCode + ".png");
}
FileOutputStream fos = new FileOutputStream(file);
lastbitmap.compress(Bitmap.CompressFormat.PNG, quailty, fos);
} catch (IOException e) {
e.printStackTrace();
return false;
}
return true;
}
I knwo there is already an question like this. But its solution was not suitable for me because with the Sehellfolder Methode you can only get 16x16 and 32x32 sized icons.
I have extracted a HICO with size of 256x256 and want to convert it into and Java Image like BufferedImage. I found and method for it to. But it does not work properly:
public static BufferedImage getIcon(final WinDef.HICON hIcon,int ICON_SIZE,short ICON_DEPTH,int ICON_BYTE_SIZE) {
final int width = ICON_SIZE;
final int height = ICON_SIZE;
final short depth = ICON_DEPTH;
final BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
final Memory lpBitsColor = new Memory(width * height * depth / ICON_BYTE_SIZE);
final Memory lpBitsMask = new Memory(width * height * depth / ICON_BYTE_SIZE);
final WinGDI.BITMAPINFO info = new WinGDI.BITMAPINFO();
final WinGDI.BITMAPINFOHEADER hdr = new WinGDI.BITMAPINFOHEADER();
info.bmiHeader = hdr;
hdr.biWidth = width;
hdr.biHeight = height;
hdr.biPlanes = 1;
hdr.biBitCount = depth;
hdr.biCompression = WinGDI.BI_RGB;
final WinDef.HDC hDC = User32.INSTANCE.GetDC(null);
final WinGDI.ICONINFO piconinfo = new WinGDI.ICONINFO();
User32.INSTANCE.GetIconInfo(hIcon, piconinfo);
GDI32.INSTANCE.GetDIBits(hDC, piconinfo.hbmColor, 0, height, lpBitsColor, info, WinGDI.DIB_RGB_COLORS);
GDI32.INSTANCE.GetDIBits(hDC, piconinfo.hbmMask, 0, height, lpBitsMask, info, WinGDI.DIB_RGB_COLORS);
int r, g, b, a, argb;
int x = 0, y = height - 1;
for (int i = 0; i < lpBitsColor.size(); i = i + 3) {
b = lpBitsColor.getByte(i) & 0xFF;
g = lpBitsColor.getByte(i + 1) & 0xFF;
r = lpBitsColor.getByte(i + 2) & 0xFF;
a = 0xFF - lpBitsMask.getByte(i) & 0xFF;
argb = a << 24 | r << 16 | g << 8 | b;
image.setRGB(x, y, argb);
x = (x + 1) % width;
if (x == 0) {
y--;
}
}
User32.INSTANCE.ReleaseDC(null, hDC);
GDI32.INSTANCE.DeleteObject(piconinfo.hbmColor);
GDI32.INSTANCE.DeleteObject(piconinfo.hbmMask);
return image;
}
Resulting Image
Do you know andy method that works better?
EDIT:
public static BufferedImage getImageByHICON(final int width, final int height, final WinNT.HANDLE hicon, final WinGDI.BITMAPINFOHEADER info) {
final WinGDI.ICONINFO iconinfo = new WinGDI.ICONINFO();
try {
// GDI32 g32 = GDI32.INSTANCE;
// get icon information
if (!User32.INSTANCE.GetIconInfo(new WinDef.HICON(hicon.getPointer()), iconinfo)) { return null; }
final WinDef.HWND hwdn = new WinDef.HWND();
final WinDef.HDC dc = User32.INSTANCE.GetDC(hwdn);
if (dc == null) {
return null; }
try {
final int nBits = width * height * 4;
// final BitmapInfo bmi = new BitmapInfo(1);
final Memory colorBitsMem = new Memory(nBits);
// // Extract the color bitmap
final WinGDI.BITMAPINFO bmi = new WinGDI.BITMAPINFO();
bmi.bmiHeader.biWidth = width;
bmi.bmiHeader.biHeight = -height;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biCompression = WinGDI.BI_RGB;
GDI32.INSTANCE.GetDIBits(dc, iconinfo.hbmColor, 0, height, colorBitsMem, bmi, WinGDI.DIB_RGB_COLORS);
// g32.GetDIBits(dc, iconinfo.hbmColor, 0, size, colorBitsMem,
// bmi,
// GDI32.DIB_RGB_COLORS);
final int[] colorBits = colorBitsMem.getIntArray(0, width * height);
if (info.biBitCount < 32) {
final Memory maskBitsMem = new Memory(nBits);
// // Extract the mask bitmap
GDI32.INSTANCE.GetDIBits(dc, iconinfo.hbmMask, 0, height, maskBitsMem, bmi, WinGDI.DIB_PAL_COLORS);
// g32.GetDIBits(dc, iconinfo.hbmMask, 0, size,
// maskBitsMem,
// bmi,
// // GDI32.DIB_RGB_COLORS);
final int[] maskBits = maskBitsMem.getIntArray(0, width * height);
// // // Copy the mask alphas into the color bits
for (int i = 0; i < colorBits.length; i++) {
colorBits[i] = colorBits[i] | (maskBits[i] != 0 ? 0 : 0xFF000000);
}
}
final BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
bi.setRGB(0, 0, width, height, colorBits, 0, height);
return bi;
} finally {
com.sun.jna.platform.win32.User32.INSTANCE.ReleaseDC(hwdn, dc);
}
} finally {
User32.INSTANCE.DestroyIcon(new WinDef.HICON(hicon.getPointer()));
GDI32.INSTANCE.DeleteObject(iconinfo.hbmColor);
GDI32.INSTANCE.DeleteObject(iconinfo.hbmMask);
}
}
Better Image
You need to use the method from Example 3 from this website
I'm using zxing to read barcodes from scanned images like this:
Ideally the barcode is always placed at 2/5 position but sometime the barcode is blurred, dirt or scratched, for testing purpose is required to save the bitmap sent to reader, based on this answer: Convert byte array of data type TYPE_4BYTE_ABGR to BufferedImage I'm trying to save the croppedBitmap without success, any help really appreciated.
private static String decodeFile(File file) throws IOException, NotFoundException {
BufferedImage bufferedImage = ImageIO.read(file);
LuminanceSource source = new
BufferedImageLuminanceSource(bufferedImage);
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
System.out.println(bitmap.getWidth() + " x " + bitmap.getHeight());
int width = bitmap.getWidth();
int height = bitmap.getHeight() / 5;
int top = height;
BinaryBitmap croppedBitmap = bitmap.crop(0, top, width, height);
int[] dst = new int[width * height];
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
int a = croppedBitmap.getBlackMatrix().get(i, j) ? 1 & 0xff : 0;
int b = croppedBitmap.getBlackMatrix().get(i, j) ? 1 & 0xff : 0;
int g = croppedBitmap.getBlackMatrix().get(i, j) ? 1 & 0xff : 0;
int r = croppedBitmap.getBlackMatrix().get(i, j) ? 1 & 0xff : 0;
dst[(i + 1) * j] = (a << 24) | (r << 16) | (g << 8) | b;
}
}
BufferedImage image = new BufferedImage(width, height,
BufferedImage.TYPE_INT_ARGB);
image.setRGB(0, 0, width, height, dst, 0, width);
boolean r = ImageIO.write(image, "bmp", new File("croppedBitmap.bmp"));
System.out.println("Write bmp:" + r);
Hashtable<DecodeHintType, Object> hint = new Hashtable<DecodeHintType, Object>();
hint.put(DecodeHintType.TRY_HARDER, BarcodeFormat.CODE_39);
try {
MultiFormatReader reader = new MultiFormatReader();
Result result = reader.decode(bitmap, hint);
return result.getText();
} catch (NotFoundException e) {
System.out.println("Decode failed.");
return null;
}
}
Use toBufferedImage:
BitMatrix blackMatrix = croppedBitmap.getBlackMatrix();
BufferedImage image = MatrixToImageWriter.toBufferedImage(blackMatrix);
I using Slick2D and LWJGL and i want to ask one question how to change game icon in the taskbar when i run it.
Actually depending on what you precisely want to do it can be quite hard.
The easyest way is to use Slick2d method: In GameContainer you can use the setIcon(String) method.
But on one of my personal project I had some difficulties loading images with Slick at start. So I looked for another solution with LWJGL :
public static void main(String[] args) {
AppGameContainer app;
try {
app = new AppGameContainer(new Main("Anode"));
org.lwjgl.opengl.Display.setIcon(loadIcon("resources/images/logo.png", app));
}
public static ByteBuffer[] loadIcon(String filepath,AppGameContainer app)
{
BufferedImage image = null;
try
{
image = ImageIO.read(app.getClass().getClassLoader().getResource(filepath));
}
catch (IOException e)
{
e.printStackTrace();
}
ByteBuffer[] buffers = new ByteBuffer[3];
buffers[0] = loadIconInstance(image, 128);
buffers[1] = loadIconInstance(image, 32);
buffers[2] = loadIconInstance(image, 16);
return buffers;
}
private static ByteBuffer loadIconInstance(BufferedImage image, int dimension)
{
BufferedImage scaledIcon = new BufferedImage(dimension, dimension, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = scaledIcon.createGraphics();
double ratio = 1;
if(image.getWidth() > scaledIcon.getWidth())
{
ratio = (double) (scaledIcon.getWidth()) / image.getWidth();
}
else
{
ratio = (int) (scaledIcon.getWidth() / image.getWidth());
}
if(image.getHeight() > scaledIcon.getHeight())
{
double r2 = (double) (scaledIcon.getHeight()) / image.getHeight();
if(r2 < ratio)
{
ratio = r2;
}
}
else
{
double r2 = (int) (scaledIcon.getHeight() / image.getHeight());
if(r2 < ratio)
{
ratio = r2;
}
}
double width = image.getWidth() * ratio;
double height = image.getHeight() * ratio;
g.drawImage(image, (int) ((scaledIcon.getWidth() - width) / 2), (int) ((scaledIcon.getHeight() - height) / 2),
(int) (width), (int) (height), null);
g.dispose();
byte[] imageBuffer = new byte[dimension*dimension*4];
int counter = 0;
for(int i = 0; i < dimension; i++)
{
for(int j = 0; j < dimension; j++)
{
int colorSpace = scaledIcon.getRGB(j, i);
imageBuffer[counter + 0] =(byte)((colorSpace << 8) >> 24 );
imageBuffer[counter + 1] =(byte)((colorSpace << 16) >> 24 );
imageBuffer[counter + 2] =(byte)((colorSpace << 24) >> 24 );
imageBuffer[counter + 3] =(byte)(colorSpace >> 24 );
counter += 4;
}
}
return ByteBuffer.wrap(imageBuffer);
}
I really advice you to use the Slick2d solution and is you don't reach your goal then you can switch to the more complicated one
im doing an edge detection which will detect edges of each RGB channel and then combine them to show it as a final output. im now having a problem with combining the three as it doesnt show me a binary image, instead it has some colors on it. i have checked each binary image of the RGB and it works fine which gives the black and white image. to be clearer, following is the code:
private void processActionPerformed(java.awt.event.ActionEvent evt) {
width = inputimage.getWidth(null);
height = inputimage.getHeight(null);
inputbuff = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
Graphics r = inputbuff.getGraphics();
r.drawImage(inputimage, 0, 0, null);
r.dispose();
process_red = new int[width * height];
process_green = new int[width * height];
process_blue = new int[width * height];
process_grey = new int[width * height];
process_rgb = new int[width * height];
process_combine = new int[width * height];
for (int i = 0; i < 256; i++) {
freq_red[i] = freq_green[i] = freq_blue[i] = freq_grey[i] = 0;
}
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
int clr = inputbuff.getRGB(y, x);
int red = (clr & 0x00ff0000) >> 16;
int green = (clr & 0x0000ff00) >> 8;
int blue = clr & 0x000000ff;
int grey = (11 * red + 16 * green + 5 * blue) / 32;
freq_red[red] += 1;
freq_green[green] += 1;
freq_blue[blue] += 1;
freq_grey[grey] += 1;
}
}
int threshold = 150;
for (int i = 0; i < 256; i++) {
freq_red[i] = applyThreshold(threshold, freq_red[i]);
freq_green[i] = applyThreshold(threshold, freq_green[i]);
freq_blue[i] = applyThreshold(threshold, freq_blue[i]);
freq_grey[i] = applyThreshold(threshold, freq_grey[i]);
}
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
int clr = inputbuff.getRGB(y, x);
int red = (clr & 0x00ff0000) >> 16;
int green = (clr & 0x0000ff00) >> 8;
int blue = clr & 0x000000ff;
int grey = (11 * red + 16 * green + 5 * blue) / 32;
red = freq_red[red];
green = freq_green[green];
blue = freq_blue[blue];
grey = freq_grey[grey];
int alpha = 0xff000000;
int combine = alpha | (red <<16) |(green <<8)|blue;
process_red[x * height + y] = (0xFF<<24)|(red<<16)|(red<<8)|red;
process_green[x * height + y] = (0xFF<<24)|(green<<16)|(green<<8)|green;
process_blue[x * height + y] = (0xFF<<24)|(blue<<16)|(blue<<8)|blue;
process_grey[x * height + y] = (0xFF<<24)|(grey<<16)|(grey<<8)|grey;
process_rgb[x * height + y] = clr;
process_combine[x * height + y] = combine;
}
}
image_red = new JFrame().createImage(new MemoryImageSource(width, height, process_red, 0, width));
image_green = new JFrame().createImage(new MemoryImageSource(width, height, process_green, 0, width));
image_blue = new JFrame().createImage(new MemoryImageSource(width, height, process_blue, 0, width));
image_grey = new JFrame().createImage(new MemoryImageSource(width, height, process_grey, 0, width));
image_rgb = new JFrame().createImage(new MemoryImageSource(width, height, process_rgb, 0, width));
image_combine = new JFrame().createImage(new MemoryImageSource(width, height, process_combine, 0, width));
buff_red = new BufferedImage(width,height, BufferedImage.TYPE_INT_RGB);
buff_green = new BufferedImage(width,height, BufferedImage.TYPE_INT_RGB);
buff_blue = new BufferedImage(width,height, BufferedImage.TYPE_INT_RGB);
buff_grey = new BufferedImage(width,height, BufferedImage.TYPE_INT_RGB);
buff_rgb = new BufferedImage(width,height, BufferedImage.TYPE_INT_RGB);
buff_combine = new BufferedImage(width,height, BufferedImage.TYPE_INT_RGB);
graph_red = buff_red.getGraphics();
graph_green = buff_green.getGraphics();
graph_blue = buff_blue.getGraphics();
graph_grey = buff_grey.getGraphics();
graph_rgb = buff_rgb.getGraphics();
graph_combine = buff_combine.getGraphics();
graph_red.drawImage(image_red, 0, 0, null);
graph_green.drawImage(image_green, 0, 0, null);
graph_blue.drawImage(image_blue, 0, 0, null);
graph_grey.drawImage(image_grey, 0, 0, null);
graph_rgb.drawImage(image_rgb, 0, 0, null);
graph_combine.drawImage(image_combine, 0, 0, null);
graph_red.dispose();
graph_green.dispose();
graph_blue.dispose();
graph_grey.dispose();
graph_rgb.dispose();
graph_combine.dispose();
repaint();
}
i suspected that the problem is with the alpha value:
int alpha = 0xff000000;
int combine = alpha | (red <<16) | (green <<8)|blue;
however, when i removed the alpha value it doesnt display anything. can anyone please help me? thanks in advance!
I am guessing that freq_red etc. are byte arrays. If so then you are being bitten by byte sign extension.
Try replacing this
red = freq_red[red];
green = freq_green[green];
blue = freq_blue[blue];
grey = freq_grey[grey];
with this:
red = freq_red[red] & 0xFF;
green = freq_green[green] & 0xFF;
blue = freq_blue[blue] & 0xFF;
grey = freq_grey[grey] & 0xFF;
Update: your method is longer than it needs to be because of all the temporary images (graph_red etc.) You can avoid them by defining a method like this:
private BufferedImage wrapPixelArray(int width,
int height,
int[] process) {
DataBuffer db = new DataBufferInt(process, width * height);
SampleModel sm =
new SinglePixelPackedSampleModel(DataBuffer.TYPE_INT, width, height, MASK);
WritableRaster wr =
Raster.createWritableRaster(sm, db, null);
return new BufferedImage(RGB, wr, false, null);
}
private static final int[] MASK = {0xFF0000, 0xFF00, 0xFF};
private static final ColorModel RGB =
new DirectColorModel(32, MASK[0], MASK[1], MASK[2]);