影象處理之影象快速插值放縮演算法
阿新 • • 發佈:2019-01-02
演算法思想:
基於雙線性演算法的分解,分別進行水平與垂直兩個方向的放縮,完成對整張影象的放大或
者縮小。基於的數學思想為矩陣的乘法,對一個scale矩陣可以拆分為水平與垂直方向的兩
個關聯矩陣,具體如下:
程式解釋:
類ScaleFilter完成對影象的快速放大與縮小,接受輸入引數為XY方向的放縮比例值。
hscal, vscale的預設值為1.5f即將輸入影象在XY放大1.5倍。XY方向的Scale方法參考與運用
了移動視窗的演算法。感興趣可以自己研究,我也是改寫一段c語言程式碼得到。感覺非常的精妙。
程式效果如下:
Scale Filter的原始碼如下:
後注:其效果近似與雙線性內插值演算法,但是執行速度卻是它的幾十倍之多,感興趣者package com.gloomyfish.filter.study; /** * @author gloomyfish * @date 2012-09-23 * @BLOGPAGE:http://blog.csdn.net/jia20003 */ import java.awt.image.BufferedImage; import java.awt.image.ColorModel; public class ScaleFilter extends AbstractBufferedImageOp { /** * default will zoom in 2.0 * input size of original image. */ private float hscale = 1.5f; private float vscale = 1.5f; public ScaleFilter() { } public void setHscale(float hscale) { this.hscale = hscale; } public void setVscale(float vscale) { this.vscale = vscale; } @Override public BufferedImage filter(BufferedImage src, BufferedImage dest) { int width = src.getWidth(); int height = src.getHeight(); if ( dest == null ) dest = createCompatibleDestImage( src, null ); // initialization pixel data int[] inPixels = new int[width*height]; int outwidth = (int)(hscale * (float)width); int outheight = (int)(vscale * (float)height); int[] outhPixels = new int[outwidth*height]; int[] outPixels = new int[outwidth*outheight]; // start to zoom in/out here getRGB( src, 0, 0, width, height, inPixels ); hscale(inPixels, outhPixels, width, height); vscale(outhPixels, outPixels, outwidth, height); // create buffered image and return it with result image data setRGB( dest, 0, 0, outwidth, outheight, outPixels); return dest; } public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel dstCM) { if ( dstCM == null ) dstCM = src.getColorModel(); int outwidth = (int)(hscale * (float)src.getWidth()); int outheight = (int)(vscale * (float)src.getHeight()); return new BufferedImage(dstCM, dstCM.createCompatibleWritableRaster(outwidth, outheight), dstCM.isAlphaPremultiplied(), null); } private void hscale(int[] input, int[] output, int width, int height) { int ta1 = 0, tr1 = 0, tg1 = 0, tb1 = 0; int ta2 = 0, tr2 = 0, tg2 = 0, tb2 = 0; int sumred = 0, sumgreen = 0, sumblue = 0; double accred = 0, accgreen = 0, accblue = 0; int p, q; int outwidth = (int)(this.hscale * width); double area = (outwidth * width); int inCol = 0, outCol = 0; int inIndex1 = 0, inIndex2 = 0, outIndex = 0; for (int row = 0; row < height; row++) { q = width; p = outwidth; accred = accgreen = accblue = 0; inCol = outCol = 0; while (outCol < outwidth) { if(outCol == 299) { System.out.println("what are you doing..."); } if ((inCol + 1) < 2) { inIndex1 = row * width + inCol; inIndex2 = row * width + (inCol + 1); ta1 = (input[inIndex1] >> 24) & 0xff; tr1 = (input[inIndex1] >> 16) & 0xff; tg1 = (input[inIndex1] >> 8) & 0xff; tb1 = input[inIndex1] & 0xff; ta2 = (input[inIndex2] >> 24) & 0xff; tr2 = (input[inIndex2] >> 16) & 0xff; tg2 = (input[inIndex2] >> 8) & 0xff; tb2 = input[inIndex2] & 0xff; sumred = p * tr1 + (outwidth - p) * tr2; sumgreen = p * tg1 + (outwidth - p) * tg2; sumblue = p * tb1 + (outwidth - p) * tb2; } else { inIndex1 = row * width + inCol; ta1 = (input[inIndex1] >> 24) & 0xff; tr1 = (input[inIndex1] >> 16) & 0xff; tg1 = (input[inIndex1] >> 8) & 0xff; tb1 = input[inIndex1] & 0xff; sumred = outwidth * tr1; sumgreen = outwidth * tg1; sumblue = outwidth * tb1; } if (p < q) { accred += sumred * p; accgreen += sumgreen * p; accblue += sumblue * p; q -= p; p = outwidth; inCol++; } else { accred += sumred * q; accgreen += sumgreen * q; accblue += sumblue * q; outIndex = row * outwidth + outCol; output[outIndex] = ta1 << 24 | ((int)(accred / area) << 16) | ((int)(accgreen / area) << 8) | (int)(accblue / area); accred = accgreen = accblue = 0; p -= q; q = width; outCol++; } } } } private void vscale(int[] input, int[] output, int width, int height) { int ta1 = 0, tr1 = 0, tg1 = 0, tb1 = 0; int ta2 = 0, tr2 = 0, tg2 = 0, tb2 = 0; int sumred = 0, sumgreen = 0, sumblue = 0; double accred = 0, accgreen = 0, accblue = 0; int inRow = 0, outRow = 0; int inIndex1 = 0, inIndex2 = 0, outIndex = 0; int p, q; int ih = height; int oh = (int)(height * vscale); int area = (ih * oh); for (int col = 0; col < width; col++) { q = ih; p = oh; accred = accgreen = accblue = 0; inRow = outRow = 0; while (outRow < oh) { if (inRow+1 < ih) { inIndex1 = inRow * width + col; inIndex2 = (inRow+1) * width + col; ta1 = (input[inIndex1] >> 24) & 0xff; tr1 = (input[inIndex1] >> 16) & 0xff; tg1 = (input[inIndex1] >> 8) & 0xff; tb1 = input[inIndex1] & 0xff; ta2 = (input[inIndex2] >> 24) & 0xff; tr2 = (input[inIndex2] >> 16) & 0xff; tg2 = (input[inIndex2] >> 8) & 0xff; tb2 = input[inIndex2] & 0xff; sumred = p * tr1 + (oh - p) * tr2; sumgreen = p * tg1 + (oh - p) * tg2; sumblue = p * tb1 + (oh - p) * tb2; } else { inIndex1 = inRow * width + col; ta1 = (input[inIndex1] >> 24) & 0xff; tr1 = (input[inIndex1] >> 16) & 0xff; tg1 = (input[inIndex1] >> 8) & 0xff; tb1 = input[inIndex1] & 0xff; sumred = oh * tr1; sumgreen = oh * tg1; sumblue = oh * tb1; } if (p < q) { accred += sumred * p; accgreen += sumgreen * p; accblue += sumblue * p; q -= p; p = oh; inRow++; } else { accred += sumred * q; accgreen += sumgreen * q; accblue += sumblue * q; outIndex = outRow * width + col; output[outIndex] = ta1 << 24 | ((int)(accred / area) << 16) | ((int)(accgreen / area) << 8) | (int)(accblue / area); accred = accgreen = accblue = 0; p -= q; q = ih; outRow++; } } } } }
可以自己測試。證明我沒有信口開河。