一个Java写的用来构建影像金字塔的Bitmap类
来源:互联网 发布:ios 九宫格算法 编辑:程序博客网 时间:2024/06/07 02:25
一个Java写的用来构建金字塔影像的Bitmap类
cheungmine
2012
下面每个图像都是256x256像素。目的就是把这4幅影像合成一个256x256的图像,即:
Ln+1 = Fn(00, 01, 10, 11);
Ln+1表示第n+1层金字塔图像块。它是在第n层金字塔的基础上创建的。
处理前的第n层金字塔(4个瓦片):
00 | 01
----------
10 | 11
处理后的第n+1层金字塔(1个瓦片):
(1) 最邻近点采样得到的 (2) 4像素取平均值得到的(双线性差值得特例)
我写的Java源代码:
/****************************************************************************** * BitmapDecoder.java * Read and Write DIB bitmap: * only 24-bits supported currently. * Author: * cheungmine *****************************************************************************///package imagery.bitmap;import java.io.Closeable;import java.lang.*;import java.io.File;import java.io.FileNotFoundException;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;// Note: Bitmap is always LittleEndian// JVM is always BigEndianpublic class BitmapDecoder { private static final int BMPFILE_HEADER_SIZE = 54; private static final short BMPFILE_TAG_BM = 0x4D42; // BITMAPFILEHEADER // private short tagBM; // 0x4D42 private int bfSize; // bytes size of file private short bfReserved1; // 0 private short bfReserved2; // 0 private int bfOffBits; // offset from begin to image data // BITMAPINFOHEADER // private int biSize; // size of info block private int width; // width pixels private int height; // height pixels private short biPlanes; // plane == 1 private short biBitCount; // color bits (1, 4, 8, 24, 32) private int biCompression; // compression mode: 0 - not; 1 - 8bits; 2 - 4bits private int biSizeImage; // images data size = 4*n private int biXPelsPerMeter; // horizontal pixels per meter, in DIB is 00H private int biYPelsPerMeter; // vertical pixels per meter, in DIB is 00H private int biClrUsed; // 0 private int biClrImportant; // 0 // RGBQUADs: ignored by 24, 32 bits bitmap // sizeof(RGBQUAD)==4 // biBitCount = 1, 4, 8 // total RGBQUADs size = sizeof(RGBQUAD)*(2^biBitCount). bytes private byte [] _RGBQUADs = null; // file handle // private FileInputStream _inStream = null; private int _widthBytes = 0; private byte [] _header = null; private static short bytes2short(int _0, int _1) { return (short)(((_1<<8)&0xff00) | (_0&0xff)); } private static int bytes2int(int _0, int _1, int _2, int _3) { return (int)(((_3<<24)&0xff000000)|((_2<<16)&0xff0000)|((_1<<8)&0xff00)|(_0&0xff)); } private static void closeStream(Closeable stream) { try { if (stream != null) { stream.close(); } } catch (IOException e) { throw new ImageryException(e); } catch (Exception e) { throw new ImageryException(e); } } private short readShort(byte [] b, int offset) { return bytes2short(b[offset], b[offset+1]); } private int readInt(byte [] b, int offset) { return bytes2int(b[offset], b[offset+1], b[offset+2], b[offset+3]); } private void readBitmapFileHeader(FileInputStream stream) { try { byte [] header = new byte[BMPFILE_HEADER_SIZE]; if (BMPFILE_HEADER_SIZE != stream.read(header)) { throw new ImageryException(new BitmapReadException("Bitmap header not found")); } int pos = 0; tagBM = readShort(header, pos); pos += 2; if (tagBM != BMPFILE_TAG_BM) { throw new ImageryException(new BitmapReadException("BM tag not found")); } bfSize = readInt(header, pos); pos += 4; bfReserved1 = readShort(header, pos); pos += 2; bfReserved2 = readShort(header, pos); pos += 2; bfOffBits = readInt(header, pos); pos += 4; biSize = readInt(header, pos); pos += 4; width = readInt(header, pos); pos += 4; height = readInt(header, pos); pos += 4; biPlanes = readShort(header, pos); pos += 2; biBitCount = readShort(header, pos); pos += 2; biCompression = readInt(header, pos); pos += 4; biSizeImage = readInt(header, pos); pos += 4; biXPelsPerMeter= readInt(header, pos); pos += 4; biYPelsPerMeter= readInt(header, pos); pos += 4; biClrUsed= readInt(header, pos); pos += 4; biClrImportant= readInt(header, pos); pos += 4; if (pos != BMPFILE_HEADER_SIZE) { throw new RuntimeException("Application has error"); } _widthBytes = calcWidthBytes(); _header = header; } catch (IOException e) { throw new ImageryException(e); } } private void readBitmapRGBQUADs(FileInputStream stream) throws BitmapReadException { if (biClrUsed > 0) { _RGBQUADs = new byte[4*biClrUsed]; try { if (4*biClrUsed != stream.read(_RGBQUADs)) { throw new BitmapReadException("Read RGBQUAD error."); } } catch (IOException e) { throw new ImageryException(e); } } } private int calcWidthBytes() { int widthBytes = 0; switch (biBitCount) { case 1: // 2-colors widthBytes = (width + 7)/8; break; case 4: // 16-colors widthBytes = (width+1)/2; break; case 8: // 256-colors widthBytes = width; break; case 24: // 24-bits true colors:rgb widthBytes = width*3; break; case 32: // 32 bits true colors: rgba widthBytes = width*4; break; } return ((widthBytes+3)/4)*4; } public BitmapDecoder(String bmpPathfile) { try { FileInputStream stream = new FileInputStream(new File(bmpPathfile)); readBitmapFileHeader(stream); readBitmapRGBQUADs(stream); _inStream = stream; } catch (NullPointerException e) { throw new ImageryException(e); } catch (FileNotFoundException e) { throw new ImageryException(e); } catch (SecurityException e) { throw new ImageryException(e); } catch (IOException e) { throw new ImageryException(e); } catch (Exception e) { throw new ImageryException(e); } } public BitmapDecoder(File fileBmp) { try { FileInputStream stream = new FileInputStream(fileBmp); readBitmapFileHeader(stream); readBitmapRGBQUADs(stream); _inStream = stream; } catch (NullPointerException e) { throw new ImageryException(e); } catch (FileNotFoundException e) { throw new ImageryException(e); } catch (SecurityException e) { throw new ImageryException(e); } catch (IOException e) { throw new ImageryException(e); } catch (Exception e) { throw new ImageryException(e); } } public void open(String bmpPathfile) { close(); try { FileInputStream stream = new FileInputStream(new File(bmpPathfile)); readBitmapFileHeader(stream); readBitmapRGBQUADs(stream); _inStream = stream; } catch (NullPointerException e) { throw new ImageryException(e); } catch (FileNotFoundException e) { throw new ImageryException(e); } catch (SecurityException e) { throw new ImageryException(e); } catch (IOException e) { throw new ImageryException(e); } catch (Exception e) { throw new ImageryException(e); } } public void close() { FileInputStream stream = _inStream; _inStream = null; closeStream(stream); } public FileInputStream getStream() { return _inStream; } public int readBytes(byte [] b, int len) { try { return _inStream.read(b, 0, len); } catch (IOException e) { throw new ImageryException(e); } } public int readLines(byte [] b, int numLines) { try { return _inStream.read(b, 0, _widthBytes*numLines); } catch (IOException e) { throw new ImageryException(e); } } public int getSizeImage() { return biSizeImage; } public int getColorBits() { return biBitCount; } public int getWidthPixels() { return width; } public int getHeightPixels() { return height; } public int getWidthBytes() { return _widthBytes; } public byte [] getBmpHeader() { return _header; } public void printBmpHeader() { // BITMAPINFOHEADER // System.out.println("----------- BITMAPFILEHEADER -----------"); System.out.println("file tag: " + tagBM); System.out.println("bytes size of file: " + bfSize); System.out.println("bfReserved1: " + bfReserved1); System.out.println("bfReserved2: " + bfReserved2); System.out.println("image data offset: " + bfOffBits); // BITMAPINFOHEADER System.out.println("----------- BITMAPINFOHEADER -----------"); System.out.println("size of info block: " + biSize); System.out.println("width pixels: " + width); System.out.println("height pixels: " + height); System.out.println("bit plane: " + biPlanes); System.out.println("color bits: " + biBitCount); System.out.println("compression mode: " + biCompression); System.out.println("images data size bytes: "+ biSizeImage); System.out.println("horizontal pixels per meter: " + biXPelsPerMeter); System.out.println("vertical pixels per meter: " + biYPelsPerMeter); System.out.println("colors Used: " + biClrUsed); System.out.println("colors Important: " + biClrImportant); // RGBQUAD if (_RGBQUADs==null) { System.out.println("----------- RGBQUAD NOT FOUND -----------"); } else { System.out.println("----------- RGBQUAD TABLE -----------"); for (int i=0; i<biClrUsed; i++) { System.out.println(i+":("+ (_RGBQUADs[i*4+0]&0xff)+","+ (_RGBQUADs[i*4+1]&0xff)+","+ (_RGBQUADs[i*4+2]&0xff)+","+ (_RGBQUADs[i*4+3]&0xff)+")"); } } } /** * ------------ * | 00 | 01 | -------- * ------------ => | | * | 10 | 11 | -------- * ------------ */ private static void calcPixel(byte [] dst, int off, byte [] src, int off_00, int off_01, int off_10, int off_11) { int b00 = src[off_00+0]&0xff; int b01 = src[off_01+0]&0xff; int g00 = src[off_00+1]&0xff; int g01 = src[off_01+1]&0xff; int r00 = src[off_00+2]&0xff; int r01 = src[off_01+2]&0xff; int b10 = src[off_10+0]&0xff; int b11 = src[off_11+0]&0xff; int g10 = src[off_10+1]&0xff; int g11 = src[off_11+1]&0xff; int r10 = src[off_10+2]&0xff; int r11 = src[off_11+2]&0xff; dst[off+0] = (byte)((b00+b01+b10+b11)/4); dst[off+1] = (byte)((g00+g01+g10+g11)/4); dst[off+2] = (byte)((r00+r01+r10+r11)/4); } public static void buildPyramid(File outputBmp, int bmpWidthPixels, int bmpHeightPixels, BitmapDecoder _00, BitmapDecoder _01, BitmapDecoder _10, BitmapDecoder _11) throws BitmapReadException { if (_00.getWidthPixels() != _01.getWidthPixels() || _10.getWidthPixels() != _11.getWidthPixels() || _00.getWidthPixels() != _11.getWidthPixels() || _00.getHeightPixels() != _01.getHeightPixels() || _10.getHeightPixels() != _11.getHeightPixels() || _00.getHeightPixels() != _11.getHeightPixels()) { throw new BitmapReadException("Bitmaps size not matched."); } if (_00.getColorBits() != _01.getColorBits() || _10.getColorBits() != _11.getColorBits() || _00.getColorBits() != _11.getColorBits()) { throw new BitmapReadException("Bitmaps colorbits not matched."); } if (bmpWidthPixels != bmpHeightPixels) { //??TODO: Should we support a rectangle one throw new BitmapReadException("Width not equal with height for output bitmap."); } if (bmpWidthPixels != _00.getWidthPixels() || bmpHeightPixels != _00.getHeightPixels()) { throw new BitmapReadException("Bitmap not square."); } FileOutputStream outStream = null; try { outStream = new FileOutputStream(outputBmp); outStream.write(_00.getBmpHeader()); int el = bmpWidthPixels; // length of edge int bpp = _00.getColorBits()/8; // Bytes Per Pixel int wb = _00.getWidthBytes(); // Width Bytes byte [] rb1 = new byte[wb*2]; // 2-lines buffer byte [] rb2 = new byte[wb*2]; // 2-lines buffer byte [] dst = new byte[wb]; // 1-lines buffer int i, n, r1, r2; while ((r1=_10.readLines(rb1, 2))==wb*2 && (r2=_11.readLines(rb2, 2))==wb*2) { for (n=0; n<el/2; n++) { i = n*2*bpp; // source calcPixel(dst, n*bpp, rb1, i, i+bpp, wb+i, wb+i+bpp); } for (n=el/2; n<el; n++) { i = (n-el/2)*2*bpp; // source calcPixel(dst, n*bpp, rb2, i, i+bpp, wb+i, wb+i+bpp); } outStream.write(dst); } while ((r1=_00.readLines(rb1, 2))==wb*2 && (r2=_01.readLines(rb2, 2))==wb*2) { for (n=0; n<el/2; n++) { i = n*2*bpp; // source calcPixel(dst, n*bpp, rb1, i, i+bpp, wb+i, wb+i+bpp); } for (n=el/2; n<el; n++) { i = (n-el/2)*2*bpp; // source calcPixel(dst, n*bpp, rb2, i, i+bpp, wb+i, wb+i+bpp); } outStream.write(dst); } } catch (IOException e) { throw new ImageryException(e); } finally { closeStream(outStream); } }}
/****************************************************************************** * ImageryException.java * *****************************************************************************///package imagery.bitmap;import java.io.*;class ImageryException extends RuntimeException { private final String _stackTrace; public Exception originalException; public ImageryException(Exception e) { super(e.toString()); originalException = e; StringWriter sw = new StringWriter(); e.printStackTrace(new PrintWriter(sw)); _stackTrace = sw.toString(); } public void printStackTrace() { printStackTrace(System.err); } public void printStackTrace(java.io.PrintStream s) { synchronized(s) { s.print(getClass().getName() + ": "); s.print(_stackTrace); } } public void printStackTrace(java.io.PrintWriter s) { synchronized(s) { s.print(getClass().getName() + ": "); s.print(_stackTrace); } } public void rethrow() throws Throwable { throw originalException; }}
/****************************************************************************** * BitmapReadException.java * *****************************************************************************///package imagery.bitmap;import java.io.*;public class BitmapReadException extends Exception { public BitmapReadException() { super(); } public BitmapReadException(String message) { super(message); } public BitmapReadException(String message, Throwable cause) { super(message, cause); } public BitmapReadException(Throwable cause) { super(cause); }}
测试代码:
/* * ------------ * | 00 | 01 | -------- * ------------ => | | * | 10 | 11 | -------- * ------------ */ public void testResampleBMP24() throws Exception { String srcdir = "C:/nv_workspace/zebra/sandbox/mapred/data/"; BitmapDecoder tile_00 = new BitmapDecoder(srcdir+"hadoop_0-0.bmp"); BitmapDecoder tile_01 = new BitmapDecoder(srcdir+"hadoop_0-1.bmp"); BitmapDecoder tile_10 = new BitmapDecoder(srcdir+"hadoop_1-0.bmp"); BitmapDecoder tile_11 = new BitmapDecoder(srcdir+"hadoop_1-1.bmp"); tile_00.printBmpHeader(); assertEquals(tile_00.getColorBits(), 24); assertEquals(tile_00.getWidthPixels(), 256); assertEquals(tile_00.getHeightPixels(), 256); BitmapDecoder.buildPyramid(new File(srcdir+"hadoop_out.bmp"), tile_00.getWidthPixels(), tile_00.getHeightPixels(), tile_00, tile_01, tile_10, tile_11); tile_00.close(); tile_01.close(); tile_10.close(); tile_11.close(); }
结论:
需要注意的是,Java的byte是有符号的,而像素的值是无符号的,需要(见calcPixel)
int iv = bv&0xff;
处理以变成无符号的.这个小小的BUG折腾我一天时间.最后把像素打印出来一个个分析才知道原来Java这么恶心.
同样功能的代码在C中需要100行的话,Java里就需要200行.无语啊!
cheungmine
- 一个Java写的用来构建影像金字塔的Bitmap类
- ARCGIS构建影像金字塔文件提高geoserver发布影像后的加载效率
- 建立影像金字塔的意义
- 建立影像金字塔的意义
- ArcGIS影像构建金字塔小窍门
- 写了一个用来写log信息的小程序
- 一个自己写的用来搜索各种文件格式生成txt清单的java工具
- 【React】一个用来构建用户界面的 JavaScript 库
- 用FWtools 切割影像金字塔可能出现的问题
- GDAL-读取影像的金字塔,生成快视图
- 写一个UIColor的分类, 用来生成随机的颜色
- 自己写的一个存储过程例子,用来增加字段
- 写一个可以用来设置 DNS 服务器的 bat 文件
- sift之一:高斯金字塔的构建
- 一个网站的金字塔战略
- 一个网站的金字塔战略
- 一个网站的金字塔战略
- 输出一个金字塔的图形
- hdu2.1.8
- hdu2.2.1
- hdu.2.2.2
- hdu 3911 Black And White 线段树
- JavaMail学习笔记(三)、使用SMTP协议发送电子邮件(全)
- 一个Java写的用来构建影像金字塔的Bitmap类
- 行进中的总结——读书笔记
- hdu 1068 Girls and Boys 二分匹配
- Android ApiDemos示例解析(29):App->Notification->Status Bar
- 开端--我想做产品
- JavaMail学习笔记(四)、使用POP3协议接收并解析电子邮件(全)
- hdu1008
- JavaMail学习笔记(五)、使用IMAP协议接收并解析电子邮件
- 素数计数公式全面拉丁化改写-小有改进-Meissel公式-梅塞尔-Lehmer公式-莱梅=勒梅尔-筛法三种形式-孟庆余公式