最近要處理一些新聞中的廣告圖檔,其中比較多的是含二維碼的圖檔。簡單寫了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, , , 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 = ; y < height; y++) {
for (int x = ; 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(, , ).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 = ;
int min = ;
for (int i = -edge; i < edge + ; i++)
{
for (int j = -edge; j < edge + ; j++)
{
// System.out.println("x:"+(x+i));
// System.out.println("y:"+(y+j));
if (x + i < || x + i > w-)
continue;
if (y + j < || y + j > h-)
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 > ? max - min : ;
}
或者簡單的視窗均值,這裡也是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 == ? : gray[x - ][y]) + (x == || y == ? : gray[x - ][y - ])
+ (x == || y == h - ? : gray[x - ][y + ]) + (y == ? : gray[x][y - ])
+ (y == h - ? : gray[x][y + ]) + (x == w - ? : gray[x + ][y])
+ (x == w - || y == ? : gray[x + ][y - ])
+ (x == w - || y == h - ? : gray[x + ][y + ]);
return rs / ;
}
這樣每個像素點會因為不同的計算方法(或者說不同程度受周邊像素權重影響),得到一個表示值,和經驗門檻值進行對比,進行二值。當然還有其他二值方法,大多是微分或者類卷積的對梯度變化加強。
public static BufferedImage loaclTOBinatry(BufferedImage bi,int T) throws IOException
{
int h = bi.getHeight();// 擷取圖像的高
int w = bi.getWidth();// 擷取圖像的寬
int rgb = bi.getRGB(, );// 擷取指定坐标的ARGB的像素值
int[][] gray = new int[w][h];
for (int x = ; x < w; x++)
{
for (int y = ; 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 = ; x < w; x++)
{
for (int y = ; y < h; y++)
{
// if(gray[x][y]<SW){
// if (getAverageColor(gray, x, y, w, h) > SW)//局部均值
// {
if (getMaxMinColor(gray, x, y, w, h, ) > SW)//局部拉伸
{
int max = new Color(, , ).getRGB();
nbi.setRGB(x, y, max);
} else
{
int min = new Color(, , ).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) / ;
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;
}
以上就這些吧,有興趣的可以評論留言,我看到會盡快回答的。