crop white background from Image

F

Franz

Hi,

I would like to crop some white background area (usually at the bottom
of the picture) of an image. For example on this image (URL:
http://www.freistil24.de/images/KANIMAL-Black-white.jpg) crop the top
and bottom white area. In my case it is usally text, but the principle
is the same.

I am using Java 1.5 and AWT. Is there any way to get the range of the
white area to clip / crop it?

Thanks in advance,
Franz
 
S

shakah

Hi,

I would like to crop some white background area (usually at the bottom
of the picture) of an image. For example on this image (URL:http://www.freistil24.de/images/KANIMAL-Black-white.jpg) crop the top
and bottom white area. In my case it is usally text, but the principle
is the same.

I am using Java 1.5 and AWT. Is there any way to get the range of the
white area to clip / crop it?

Thanks in advance,
Franz

You might want to check out ImageMagick to see if it does this kind of
cropping:
http://www.imagemagick.org/script/index.php

Otherwise, I've used java.awt.image.PixelGrabber to do this kind of
stuff in the past, along the lines of the following (you'd have to
modify the code to write the non-all-white lines to another image, of
course):

public class bgcrop {
public static void main(String [] args)
throws Exception {
System.exit(new bgcrop().process(args)) ;
}

private static boolean isWhite(int pixel) {
int alpha = (pixel >> 24) & 0xff;
int red = (pixel >> 16) & 0xff;
int green = (pixel >> 8) & 0xff;
int blue = (pixel ) & 0xff;

return (0xFF==red && 0xFF==green && 0xFF==blue) ;
}

private static boolean areAllWhite(int [] pixels) {
for(int pixel=0; pixel<pixels.length; ++pixel) {
if(!isWhite(pixels[pixel])) {
return false ;
}
}
return true ;
}

private int process(String [] args)
throws Exception {
int exit_code = 0 ;

for(int arg=0; arg<args.length; ++arg) {
javax.swing.ImageIcon ii = new
javax.swing.ImageIcon(args[arg]) ;
java.awt.Image img = ii.getImage() ;
int [] row_pixels = new int[ii.getIconWidth()] ;
for(int row=0; row<ii.getIconHeight(); ++row) {
// ...grab this row's pixels
java.awt.image.PixelGrabber pg
= new java.awt.image.PixelGrabber(
img, 0, row, ii.getIconWidth()
,1, row_pixels, 0, ii.getIconWidth()) ;
pg.grabPixels() ;
System.out.println("row " + row + ": "
+ (areAllWhite(row_pixels) ? "all white" : "not all
white")) ;
}
}

return exit_code ;
}
}
 
K

Knute Johnson

Franz said:
Hi,

I would like to crop some white background area (usually at the bottom
of the picture) of an image. For example on this image (URL:
http://www.freistil24.de/images/KANIMAL-Black-white.jpg) crop the top
and bottom white area. In my case it is usally text, but the principle
is the same.

I am using Java 1.5 and AWT. Is there any way to get the range of the
white area to clip / crop it?

Thanks in advance,
Franz

Assuming that the white area really is white you could scan through the
rows of pixels until you came to a row that had non-white pixels,
throwing away all the white rows. You could do this with columns too to
get the left and right edges.

If the pixels aren't really white you could set some sort of threshold
value for the row or a pixel that told you when to stop.
 
F

Franz

Hi shakah and Knute,

thanks for your hints. It works, but as I have quite big Images with
lots of white space, it takes a long time to calculate all rows.

But I found another much quicker way (at least for my purpose) - see
code excerpt below.

Thanks,
Franz


--- BEGIN CODE EXCERPT ---
public ByteArrayOutputStream reformatImage(ByteArrayOutputStream baos)
throws IOException, Exception {
ByteArrayInputStream bais = new
ByteArrayInputStream(baos.toByteArray());
ByteArrayOutputStream osScaledImg = null;

int picType = BufferedImage.TYPE_4BYTE_ABGR;
long startTime = System.currentTimeMillis();

PNGDecodeParam decP = new PNGDecodeParam();
PNGImageDecoder decoder = new PNGImageDecoder(bais, decP);
Raster r = decoder.decodeAsRaster();

int w = r.getWidth();
int h = r.getHeight();
int[] samplePx = new int[w - 1];

BufferedImage bimg = new BufferedImage(w, h, picType);
bimg.setData(r);

BufferedImage croppedImage = null;
int proofCount = 0;

System.out.println("start Pixel Test height: " + h + " width: " +
w);
for (int row = h - 1; row > 0 ; row--) {
r.getSamples(0, row, w-1, 1, 0, samplePx);

boolean areAllWhite = false;

if (croppedImage == null) {
proofCount++;
areAllWhite = areAllWhite(samplePx);
// System.out.println("row: " + row + " allwhite: " + areAllWhite);
}

if (!areAllWhite && croppedImage == null) {
// that the height of the new Image!
croppedImage = new BufferedImage(w, row + 1,
BufferedImage.TYPE_4BYTE_ABGR);
System.out.println("new image height " + row);
System.out.println("time used for white check " +
(System.currentTimeMillis() - startTime) + " ms gebraucht.");
break;
}

}

if (croppedImage != null) {
Graphics2D g2d;

g2d = (Graphics2D) croppedImage.getGraphics();
g2d.drawImage(bimg, 0, 0, w, h, null);
g2d.dispose();

osScaledImg = new ByteArrayOutputStream();
ImageIO.write(croppedImage, ImageFormat.PNG, osScaledImg);

TestJFC.writeOS2File(osScaledImg, "test.png");
}

System.out.println("crop finished in " + (System.currentTimeMillis()
- startTime) + " ms");
System.out.println("checked white lines: " + proofCount);

return osScaledImg;
}

private static boolean areAllWhite(int[] pixels) {
for (int pixel = 0; pixel < pixels.length; ++pixel) {
if (pixels[pixel] != 255) {
return false;
}
}
return true;
}
--- END CODE EXCERPT ---
 
S

shakah

Hi shakah and Knute,

thanks for your hints. It works, but as I have quite big Images with
lots of white space, it takes a long time to calculate all rows.

But I found another much quicker way (at least for my purpose) - see
code excerpt below.

Glad that you found something that works for you. Performance diff
could be due to reading the image via the BufferedImage class (maybe
just one actual read?) and/or to narrowing down the problem domain to
PNG files (?).

FWIW, I did play with this a bit after my post yesterday to add column-
based cropping and to read the image in all at once (when I noticed
that PixelGrabber's column-by-column reading was particularly slow). I
ended up with the following code that computed the crop rectangle,
which seemed to work OK when passed into ImageMagick's convert/crop
utility:

jc@jc-ubuntu:~/tmp/bgcrop$ cat bgcrop.java
public class bgcrop {
public static void main(String [] args)
throws Exception {
System.exit(new bgcrop().process(args)) ;
}

private static boolean isWhite(int pixel) {
int alpha = (pixel >> 24) & 0xff;
int red = (pixel >> 16) & 0xff;
int green = (pixel >> 8) & 0xff;
int blue = (pixel ) & 0xff;

return (0xFF==red && 0xFF==green && 0xFF==blue) ;
}

private static boolean areAllWhite(int [] pixels, int off, int len)
{
for(int pixel=off; pixel<off+len; ++pixel) {
if(!isWhite(pixels[pixel])) {
return false ;
}
}
return true ;
}

private static boolean isColumnAllWhite(int [] pixels, int col, int
row_len, int row_offset, int rows) {
for(int row=row_offset; row<row_offset+rows; ++row) {
int pixel=row*row_len+col ;
if(!isWhite(pixels[pixel])) {
return false ;
}
}
return true ;
}

private int process(String [] args)
throws Exception {
int exit_code = 0 ;

for(int arg=0; arg<args.length; ++arg) {
System.out.println("\n" + args[arg]) ;
javax.swing.ImageIcon ii = new
javax.swing.ImageIcon(args[arg]) ;
java.awt.Image img = ii.getImage() ;
System.out.println(" img width: " + ii.getIconWidth()) ;
System.out.println(" img height: " + ii.getIconHeight()) ;
int min_nw_row = -1 ;
int max_nw_row = -1 ;
int [] img_pixels = new int[ii.getIconHeight() *
ii.getIconWidth()] ;
// ...grab this images's pixels
java.awt.image.PixelGrabber pg
= new java.awt.image.PixelGrabber(
img, 0, 0, ii.getIconWidth()
,ii.getIconHeight(), img_pixels, 0, ii.getIconWidth()) ;
pg.grabPixels() ;
for(int row=0; row<ii.getIconHeight(); ++row) {
if(!areAllWhite(img_pixels, ii.getIconWidth()*row,
ii.getIconWidth())) {
if(min_nw_row < 0) {
min_nw_row = row ;
}
else if(row > max_nw_row) {
max_nw_row = row ;
}
}
}

// ...how about column-based cropping?
int min_nw_col = -1 ;
int max_nw_col = -1 ;
for(int col=0; col<ii.getIconWidth(); ++col) {
if(!isColumnAllWhite(img_pixels, col, ii.getIconWidth(),
min_nw_row, max_nw_row-min_nw_row)) {
if(min_nw_col < 0) {
min_nw_col = col ;
}
else if(col > max_nw_col) {
max_nw_col = col ;
}
}
}
System.out.println(" crop rect: (" + min_nw_col + "," +
min_nw_row + ") to (" + max_nw_col + "," + max_nw_row + ")") ;

}

return exit_code ;
}
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top