最近要处理一些新闻中的广告图片,其中比较多的是含二维码的图片。简单写了3种逻辑处理了下(同源不同内容,同图片;含完整二维码的图片;残缺二维码广告图片),基本达到了实际需求。有同样需求的可以参考下,言归正传,今天看到有读者问java图像怎么转bitset,下面举例一些我的处理方法。
首先图片有不同来源,有的是url,那么url首先读取成BufferedImage
URL url_url = new URL(img_url);
Image image = null;
try
{
image = ImageIO.read(url_url);
} catch (Exception e)
{
e.printStackTrace();
}
BufferedImage buf = GetImage.toBufferedImage(image);
BufferedImage binatryBuf = BinaryTest.loaclTOBinatry(buf);
ImageData imagedata = BufferedImageHelper.bufferedImageToImageData(binatryBuf);
其中的imagedata是个model类,宽,高,和图像的bitset。
public class ImageData {
private BitSet bitSet;
private int width;
private int height;
public ImageData(BitSet bitSet, int width, int height) {
this.bitSet = bitSet;
this.width = width;
this.height = height;
}
public BitSet getBitSet() {
return bitSet;
}
public void setBitSet(BitSet bitSet) {
this.bitSet = bitSet;
}
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
}
其中的GetImage.toBufferedImage(image)
public static BufferedImage toBufferedImage(Image image) {
if (image instanceof BufferedImage) {
return (BufferedImage)image;
}
image = new ImageIcon(image).getImage();
BufferedImage bimage = null;
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
try {
int transparency = Transparency.OPAQUE;
GraphicsDevice gs = ge.getDefaultScreenDevice();
GraphicsConfiguration gc = gs.getDefaultConfiguration();
bimage = gc.createCompatibleImage(
image.getWidth(null), image.getHeight(null), transparency);
} catch (HeadlessException e) {
}
if (bimage == null) {
int type = BufferedImage.TYPE_INT_RGB;
bimage = new BufferedImage(image.getWidth(null), image.getHeight(null), type);
}
Graphics g = bimage.createGraphics();
g.drawImage(image, 0, 0, null);
g.dispose();
return bimage;
}
如果BufferedImage本身就是二值的黑白图像,比如商场打印小票,那么可以用下面方法直接转换为bitset(Imagedata)
public static ImageData bufferedImageToImageData(BufferedImage buffer,
int threshold) {
if (buffer == null) {
return null;
}
int width = buffer.getWidth();
int height = buffer.getHeight();
BitSet bitSet = new BitSet(width * height);
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
bitSet.set(y * width + x, buffer.getRGB(x, y) <= threshold);
}
}
return new ImageData(bitSet, width, height);
}
public static ImageData bufferedImageToImageData(BufferedImage buffer) {
return bufferedImageToImageData(buffer, new Color(0, 0, 0).getRGB());
}
如果图像是彩色的,那么就要选择合适的二值化方法,下面举例几种:
适合检测类似二维码这种黑白色彩对比明显的图片,max-min方法
/**
* 3*3窗口求Max-Min
*
* @param gray
* @param x
* @param y
* @param w
* @param h
* @return
*/
public static int getMaxMinColor(int[][] gray, int x, int y, int w, int h, int edge)
{
int max = 0;
int min = 255;
for (int i = -edge; i < edge + 1; i++)
{
for (int j = -edge; j < edge + 1; j++)
{
// System.out.println("x:"+(x+i));
// System.out.println("y:"+(y+j));
if (x + i < 0 || x + i > w-1)
continue;
if (y + j < 0 || y + j > h-1)
continue;
if (gray[x + i][y + j] > max)
max = gray[x + i][y + j];
if (gray[x + i][y + j] < min)
min = gray[x + i][y + j];
}
}
return max - min > 0 ? max - min : 0;
}
或者简单的窗口均值,这里也是3×3
/**
* 自己加周围8个灰度值再除以9,算出其相对灰度值
*
* @param gray
* @param x
* @param y
* @param w
* @param h
* @return
*/
public static int getAverageColor(int[][] gray, int x, int y, int w, int h)
{
int rs = gray[x][y] + (x == 0 ? 255 : gray[x - 1][y]) + (x == 0 || y == 0 ? 255 : gray[x - 1][y - 1])
+ (x == 0 || y == h - 1 ? 255 : gray[x - 1][y + 1]) + (y == 0 ? 255 : gray[x][y - 1])
+ (y == h - 1 ? 255 : gray[x][y + 1]) + (x == w - 1 ? 255 : gray[x + 1][y])
+ (x == w - 1 || y == 0 ? 255 : gray[x + 1][y - 1])
+ (x == w - 1 || y == h - 1 ? 255 : gray[x + 1][y + 1]);
return rs / 9;
}
这样每个像素点会因为不同的计算方法(或者说不同程度受周边像素加权影响),得到一个表示值,和经验阈值进行对比,进行二值。当然还有其他二值方法,大多是微分或者类卷积的对梯度变化加强。
public static BufferedImage loaclTOBinatry(BufferedImage bi,int T) throws IOException
{
int h = bi.getHeight();// 获取图像的高
int w = bi.getWidth();// 获取图像的宽
int rgb = bi.getRGB(0, 0);// 获取指定坐标的ARGB的像素值
int[][] gray = new int[w][h];
for (int x = 0; x < w; x++)
{
for (int y = 0; y < h; y++)
{
gray[x][y] = getGray(bi.getRGB(x, y));
}
}
BufferedImage nbi = new BufferedImage(w, h, BufferedImage.TYPE_BYTE_BINARY);
int SW = T;// 200=0.84 //230=0.94
for (int x = 0; x < w; x++)
{
for (int y = 0; y < h; y++)
{
// if(gray[x][y]
// if (getAverageColor(gray, x, y, w, h) > SW)//局部均值
// {
if (getMaxMinColor(gray, x, y, w, h, 1) > SW)//局部拉伸
{
int max = new Color(255, 255, 255).getRGB();
nbi.setRGB(x, y, max);
} else
{
int min = new Color(0, 0, 0).getRGB();
nbi.setRGB(x, y, min);
}
}
}
return nbi;
// ImageIO.write(nbi, "jpg", new File("D:/Test/binary/二值化后_无压缩.jpg"));
}
public static int getGray(int rgb)
{
Color c = new Color(rgb);
int r = c.getRed();
int g = c.getGreen();
int b = c.getBlue();
int top = (r + g + b) / 3;
return (int) (top);
}
url转bufferImage还可以用下面的方法
public static BufferedImage getBufferedImage(String img_url)
{
BufferedInputStream bis = null;
HttpURLConnection httpUrl = null;
URL url = null;
try
{
url = new URL(img_url);
httpUrl = (HttpURLConnection) url.openConnection();
httpUrl.connect();
bis = new BufferedInputStream(httpUrl.getInputStream());
InputStream iis = bis;
BufferedImage image = ImageIO.read(iis);
return image;
} catch (MalformedURLException e)
{
e.printStackTrace();
} catch (IOException e)
{
e.printStackTrace();
} catch (ArrayIndexOutOfBoundsException e)
{
e.printStackTrace();
}
return null;
}
以上就这些吧,有兴趣的可以评论留言,我看到会尽快回答的。