Panning a BufferedImage - java

How can I delete say 50px of the leftmost vertical column of a BufferedImage, and copy that into a new BufferedImage the same size as the original BufferedImage?
class TestCopyImage {
var img: BufferedImage? = null
private val rnd = Random()
fun create(screenWidth: Int, screenHeight: Int) {
img = BufferedImage(screenWidth, screenHeight, BufferedImage.TYPE_INT_RGB)
//Grab the graphics object off the image
val graphics = img!!.createGraphics()
//val stroke: Stroke = BasicStroke(1f)
//graphics.setStroke(stroke);
// Fill the image buffer
for (i in 1..screenWidth) {
for (j in 1..screenHeight) {
val r: Int = rnd.nextInt(255)
val g: Int = rnd.nextInt(255)
val b: Int = rnd.nextInt(255)
val randomColor = Color(r, g, b)
graphics.paint = randomColor
graphics.fill(Rectangle(i , j , 1, 1))
}
}
// Get a subimage, deleting 50 pixels of the left-most vertical portion.
img = img!!.getSubimage(50, 0, screenWidth - 50 , screenHeight)
// TODO Now copy that into a new image, same size as the original buffer?
img = BufferedImage(screenWidth, screenHeight, BufferedImage.TYPE_INT_RGB)
}
}

Here's a Java version of what you can do:
int panDist = 50;
BufferedImage subImg = img.getSubimage(panDist, 0, img.getWidth() - panDist, img.getHeight());
BufferedImage newImg = new BufferedImage(img.getWidth(), img.getHeight(), img.getType());
for (int x = 0; x < subImg.getWidth(); ++x) {
for (int y = 0; y < subImg.getHeight(); ++y) {
newImg.setRGB(x, y, subImg.getRGB(x, y));
}
}
The subimage isn't really necessary though, you could skip that and just do this instead:
int panDist = 50;
BufferedImage newImg = new BufferedImage(img.getWidth(), img.getHeight(), img.getType());
for (int x = panDist; x < img.getWidth(); ++x) {
for (int y = 0; y < img.getHeight(); ++y) {
newImg.setRGB(x - panDist, y, img.getRGB(x, y));
}
}
You could also tweak that slightly to modify the image in-place instead.

Related

drawText to a specific postion of bitmap Android

I want to fill a credit card image with some text(name, surname,...) but i found problems to correctly find the starting position of the text.
I have marked my image with special pixels, I want to draw text at the start of this specific pixels but when I run the text is not aligned with them, I supposed that the specific pixel position that I calculated in the code is calculated starting from the first canvas pixel rather than the first bitmap pixel. How can I solve it? Thank you.
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Bitmap bitmap = ((BitmapDrawable)this.getDrawable()).getBitmap();
final int w = bitmap.getWidth();
final int h = bitmap.getHeight();
int pixel;
int redValue;
int blueValue;
int greenValue;
for (int x = 0; x < w; x++) {
for (int y = 0; y < h; y++) {
pixel = bitmap.getPixel(x, y);
redValue = Color.red(pixel);
blueValue = Color.blue(pixel);
greenValue = Color.green(pixel);
if (redValue == 255 && greenValue == 254 && blueValue == 0){
Paint paint = new Paint();
paint.setColor(Color.BLACK);
paint.setTextSize(35);
canvas.drawText("Some Text", x, y, paint);
}
}
}
}

Tensorflow in Android: java.lang.illegalArgumentsException

I want to put a tensorflow model on Anroid.
I recently noticed that the results of running the same data in Python and Android, respectively, are inconsistent.
After several trial and error, I found that the input data I entered when I ran the model on Android was wrong.
It was just a java.lang.IllegalArgumentException error, and I think I put the data correctly, but I have no idea what went wrong.
I used images that were transformed into image resizing and gray scale as learning data. in Python
I did the same preprocessing on Android.
My image type is .jpg
I attached my source.
Source related to image preprocessing
btntrans.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
try {
image_bitmap = resizeBitmapImage(image_bitmap, 28);
image_bitmap = RGB2GRAY(image_bitmap);
image.setImageBitmap(image_bitmap);
byte[] byteArrayRes = bitmapToByteArray(image_bitmap);
float[] inputArray = bytetofloat(byteArrayRes);
activityPrediction(inputArray);
}
catch(Exception e){
}
}
});
Everything happens when I click the button
resizeBitmapImage method
public Bitmap resizeBitmapImage(Bitmap source, int maxResolution)
{
int width = source.getWidth();
int height = source.getHeight();
int newWidth = width;
int newHeight = height;
float rate = 0.0f;
if(width > height)
{
if(maxResolution < width)
{
rate = maxResolution / (float) width;
newHeight = (int) (height * rate);
newWidth = maxResolution;
}
}
else
{
if(maxResolution < height)
{
rate = maxResolution / (float) height;
newWidth = (int) (width * rate);
newHeight = maxResolution;
}
}
return Bitmap.createScaledBitmap(source, newWidth, newHeight, true);
}
RGB2GRAY method
public Bitmap RGB2GRAY(Bitmap image){
int width = image.getWidth();
int height = image.getHeight();
Bitmap bmOut;
bmOut = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_4444);
for(int x = 0; x < width; x++){
for(int y = 0 ; y < height; y++){
int pixel = image.getPixel(x, y);
int A = Color.alpha(pixel);
int R = Color.red(pixel);
int G = Color.green(pixel);
int B = Color.blue(pixel);
R = G = B = (int)(0.299 * R + 0.587 * G + 0.114 * B);
bmOut.setPixel(x, y, Color.argb(A, R, G, B));
}
}
return bmOut;
}
bitmap to byte array method
private byte[] bitmapToByteArray(Bitmap bitmap){
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream);
return stream.toByteArray();
}
bytetofloat method
public float[] bytetofloat(byte[] array){
int[] returnArr = new int[array.length/4];
float[] returnArr1 = new float[array.length/4];
for(int i = 0 ; i < returnArr.length; i++){
//array[i] = 0;
returnArr[i] = array[i*4] & 0xFF;
if(returnArr[i] < 0 || returnArr[i]>255)
Log.d("ARRAY", returnArr[i]+" ");
returnArr1[i] = (float)returnArr[i];
}
return returnArr1;
}
When I run it with the above source, I get this error exactly.
java.lang.IllegalArgumentException: buffer with 308 elements is not
compatible with a Tensor with shape [1, 28, 28]
28 * 28 is Input image size
Before image resizing, it had an average width of 20 and a height of 36.
The strange thing is that the number 308 is changed to 306, 307 and fixed.
What can i do?
Here is my method for converting Java BufferedImage to Tensor object:
private static Tensor<?> convertImageToArray(BufferedImage bf) {
int width = bf.getWidth();
int height = bf.getHeight();
float[][][][] rgbArray = new float[1][height][width][3];
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
bf.getRaster().getPixel(i, j, rgbArray[0][i][j]);
}
}
return Tensor.create(rgbArray);
}
Your problem is probably in missed channels of your image. Float array length must be equal to
height * width * channels
of the image.

Creating/Cropping image base on number of pixels Java

How can i crop an image to a specified number of pixels or create image that the output will be base on number of pixel not rectangular shape.
By using the code below i can only get square or rectangle shape.
BufferedImage out = img.getSubimage(0, 0, 11, 11);
But it only crops it to rectangular shape
import java.io.File;
import java.io.IOException;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
public class raNd{
public static void main(String args[])throws IOException{
//image dimension
int width = 10;
int height = 10;
//create buffered image object img
BufferedImage img = new BufferedImage(width, height,
BufferedImage.TYPE_INT_ARGB);
//file object
File f = null;
//create random image pixel by pixel
for(int y = 0; y < height; y++){
for(int x = 0; x < width; x++){
int a = 255;//(int)(Math.random()*256); //alpha
int r = (int)(Math.random()*256); //red
int g = (int)(Math.random()*256); //green
int b = (int)(Math.random()*256); //blue
int p = (a<<24) | (r<<16) | (g<<8) | b; //pixel
img.setRGB(x, y, p);
}
}
//write image
try{
f = new File("/Users/kingamada/Documents/Java/Test6.png");
BufferedImage out = img.getSubimage(0, 0, 5, 2);
ImageIO.write(out, "png", f);
}catch(IOException e){
System.out.println("Error: " + e);
}
}//main() ends here
}//class ends here
Sample Picture
I want the last white pixels cropped out, so the picture will not be rectangle.
So assuming the number of pixels you need to keep is in variable int pixelsLimit;:
int pixels = 0;
for(int y = 0; y < height; y++){
for(int x = 0; x < width; x++){
int p = 0;
if (pixels < pixelsLimit) {
int a = 255;//(int)(Math.random()*256); //alpha
int r = (int)(Math.random()*256); //red
int g = (int)(Math.random()*256); //green
int b = (int)(Math.random()*256); //blue
p = (a<<24) | (r<<16) | (g<<8) | b; //pixel
}
img.setRGB(x, y, p);
++pixels;
}
}
Java images are rectangular, but people have suggested you can set the pixels you don't want to be transparent.
Ellipse2D clip = new Ellipse2D.Double(0, 0, width, height);
for(int y = 0; y < height; y++){
for(int x = 0; x < width; x++){
if(!clip.contains(x,y)){
img.setRGB(x, y, 0);
}
}
}
This could directly be added to existing code to make your image an ellipse. Another way would be to use a clipping shape and a graphics object. I've replaced your complete write image block.
//write image
try{
f = new File("Test6.png");
Ellipse2D clip = new Ellipse2D.Double(0, 0, width, height);
BufferedImage clipped = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics g = clipped.getGraphics();
g.setClip(clip); //ellipse from above.
g.drawImage(img, 0, 0, null);
g.dispose();
ImageIO.write(clipped, "png", f);
}catch(IOException e){
System.out.println("Error: " + e);
}
This compiled for me and wrote a tiny circular image.

Can't draw BufferedImage into another BufferedImage with scale

Please advise.
I'm trying to draw input BufferedImage into larger output BufferedImage (with scaling). Please, take a look at the following code:
public class Main {
public void print(BufferedImage img, int width, int height) {
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
System.out.print(img.getRGB(x, y) + " ");
}
System.out.println("");
}
}
public static void main(String[] args) {
Main app = new Main();
// create input image
int inputWidth = 2;
int inputHeight = 2;
BufferedImage inputImg = new BufferedImage(inputWidth, inputHeight, BufferedImage.TYPE_INT_ARGB);
// fill input image
for (int y = 0; y < inputHeight; y++) {
for (int x = 0; x < inputWidth; x++) {
inputImg.setRGB(x, y, y * inputWidth * (1 << 16) + x);
}
}
// print
app.print(inputImg, inputWidth, inputHeight);
// create output image
int outputWidth = 4;
int outputHeight = 4;
BufferedImage outputImg = new BufferedImage(outputWidth, outputHeight, BufferedImage.TYPE_INT_ARGB);
// draw inputImg into outputImg
Graphics2D g = outputImg.createGraphics();
g.drawImage(inputImg, 0, 0, outputImg.getWidth(), outputImg.getHeight(), 0, 0, inputImg.getWidth(), inputImg.getHeight(), null);
// print
app.print(outputImg, outputImg.getWidth(), outputImg.getHeight());
}
}
Execution produces the following output:
0 1
131072 131073
0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0
Seems like Graphics2D object works, because I'm able to draw, for example, a line calling the drawLine function. So, I think the inputImg is the source of the issue, but I can't figure out what's wrong.
UPDATE:
I've tried to use AffineTransform, but it didn't help, unfortunately.
Graphics2D g = outputImg.createGraphics();
AffineTransform at = new AffineTransform();
at.setToIdentity();
at.scale(2, 2);
g.drawImage(inputImg, at, null);
To me, this seems to be an issue with the color calculation you're using...
When I change...
inputImg.setRGB(x, y, y * inputWidth * (1 << 16) + x);
to...
int rgb = y * inputWidth * (1 << 16) + x;
inputImg.setRGB(x, y, new Color(rgb).getRGB());
I get a result, albeit a black dot. This suggests to me that by default, your calculation is generating a alpha value of 0
This can be born out in the output that they produce:
My method generates
-16777216 -16777215
-16646144 -16646143
Yours generates
0 1
131072 131073
Now, frankly, this is why I don't do this kind of calculation, not when a API is available to do it for me - but I be dumb ;P
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
public class Main {
public void print(BufferedImage img, int width, int height) {
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
System.out.print(img.getRGB(x, y) + " ");
}
System.out.println("");
}
}
public static void main(String[] args) {
Main app = new Main();
// create input image
int inputWidth = 2;
int inputHeight = 2;
BufferedImage inputImg = new BufferedImage(inputWidth, inputHeight, BufferedImage.TYPE_INT_ARGB);
// fill input image
System.out.println(inputWidth + "x" + inputHeight);
Color color = Color.RED;
for (int y = 0; y < inputHeight; y++) {
for (int x = 0; x < inputWidth; x++) {
int rgb = y * inputWidth * (1 << 16) + x;
inputImg.setRGB(x, y, new Color(rgb).getRGB());
}
}
JOptionPane.showMessageDialog(null, new JLabel(new ImageIcon(inputImg)));
// print
app.print(inputImg, inputWidth, inputHeight);
// create output image
int outputWidth = 4;
int outputHeight = 4;
BufferedImage outputImg = new BufferedImage(outputWidth, outputHeight, BufferedImage.TYPE_INT_ARGB);
// draw inputImg into outputImg
Graphics2D g = outputImg.createGraphics();
g.drawImage(inputImg, 0, 0, outputImg.getWidth(), outputImg.getHeight(), 0, 0, inputImg.getWidth(), inputImg.getHeight(), null);
g.dispose();
JOptionPane.showMessageDialog(null, new JLabel(new ImageIcon(outputImg)));
// print
app.print(outputImg, outputImg.getWidth(), outputImg.getHeight());
}
}

Java SWT: Get subset of Pixels from Image to create a new Image

I am displaying an Image from a list of Pixels as follows (this works):
private Image GetImage()
{
PaletteData palette=new PaletteData(0xff0000,0x00ff00,0x0000ff);
ImageData imageData = new ImageData(bmpHW, bmpHW,32,palette);
currentImagePixelVec = getPixelsFromBMP(0, 0, graphicsMemory);
int pixelVecLoc=0;
for (int h = 0; h<bmpHW; h++)
{
for (int w = 0; w<bmpHW; w++)
{
int p = 0;
Pixel pixel = currentImagePixelVec.get(pixelVecLoc);
p = (pixel.Alpha<<24) | (pixel.Red<<16) | (pixel.Green<<8) | pixel.Blue;
imageData.setPixel(w, h, p);
pixelVecLoc++;
}
}
imageData = imageData.scaledTo(700, 700);
Image image = ImageDescriptor.createFromImageData(imageData).createImage();
return image;
}
I am getting the user to select a rectangle of the Image as follows(this works):
if(drag)
{
GC gc1 = e.gc;
//gc.setBackground(top.getDefault().getSystemColor(SWT.COLOR_BLACK));
gc1.setAlpha(128);
int minX = Math.min(startX, endX);
int minY = Math.min(startY, endY);
int maxX = Math.max(startX, endX);
int maxY = Math.max(startY, endY);
int width = maxX - minX;
int height = maxY - minY;
gc1.fillRectangle(minX, minY, width, height);
}
I would like to create a new image from the rectangle selection:
private Image GetZoomedImage()
{
int minX = Math.min(startX, endX);
int minY = Math.min(startY, endY);
int maxX = Math.max(startX, endX);
int maxY = Math.max(startY, endY);
int width = maxX - minX;
int height = maxY - minY;
PaletteData palette=new PaletteData(0xff0000,0x00ff00,0x0000ff);
ImageData imageData = new ImageData(1300, 1300,32,palette);
int newHeight = 0;
int newWidth = 0;
for (int h = minX; h<maxX; h++)
{
for (int w = minY; w<maxY; w++)
{
int p = 0;
//Pixel pixel = currentImagePixelVec.get((h * w)-1);
int actualPix = imageDisplayed.getImageData().getPixel(h, w);
//p = (pixel.Alpha<<24) | (pixel.Red<<16) | (pixel.Green<<8) | pixel.Blue;
System.out.println("Pixel: " + Integer.toString(actualPix));
//imageData.setPixel(newWidth,newHeight, p);
imageData.setPixel(newWidth,newHeight, actualPix);
newWidth++;
}
newHeight++;
}
imageData = imageData.scaledTo(700, 700);
Image image = ImageDescriptor.createFromImageData(imageData).createImage();
return image;
}
Am I on the right track on this one?
You should only get the image data of the existing image once as this can be an expensive operation:
ImageData imageDisplayedData = imageDisplayed.getImageData();
Your new image data should be just the width and height you want:
ImageData imageData = new ImageData(width, height, 32, palette);
You can use the
public void getPixels(int x, int y, int getWidth, int[] pixels, int startIndex)
public void setPixels(int x, int y, int putWidth, int[] pixels, int startIndex)
methods of ImageData to read and write the data for a whole row at a time:
int [] pixels = new int [width];
int newRow = 0;
for (int row = minY; row < maxY; row++)
{
imageDisplayedData.getPixels(minX, row, width, pixels, 0);
imageData.setPixels(0, newRow, width, pixels, 0);
newRow++;
}

Categories

Resources