zoukankan      html  css  js  c++  java
  • 图像处理------高斯金字塔 分类: 视频图像处理 2015-07-24 15:05 63人阅读 评论(0) 收藏

    一:图像金字塔基本操作

    对一张图像不断的模糊之后向下采样,得到不同分辨率的图像,同时每次得到的

    新的图像宽与高是原来图像的1/2, 最常见就是基于高斯的模糊之后采样,得到的

    一系列图像称为高斯金字塔。




    高斯金字塔不同(DoG)又称为拉普拉斯金字塔,其计算公式如下:

    L(i) = G(i) – expand(G(i+1))

    第i层拉普拉斯金字塔是由第i层高斯金字塔减去第i+1层高斯金字塔expand之后得到。

    本文得到的DoG(Difference of Gaussian)结果如下:


    二:关键代码解析

    金字塔reduce操作实现代码如下:

    1. private BufferedImage pyramidReduce(BufferedImage src) {  
    2.     int width = src.getWidth();  
    3.        int height = src.getHeight();  
    4.        BufferedImage dest = createSubCompatibleDestImage(src, null);  
    5.        int[] inPixels = new int[width*height];  
    6.        int ow = width/2;  
    7.        int oh = height/2;  
    8.        int[] outPixels = new int[ow*oh];  
    9.        getRGB(src, 00, width, height, inPixels );  
    10.        int inRow=0, inCol = 0, index = 0, oudex =0, ta = 0;  
    11.        float[][] keneralData = this.getHVGaussianKeneral();  
    12.        for(int row=0; row<oh; row++) {  
    13.         for(int col=0; col<ow; col++) {  
    14.             inRow = 2* row;  
    15.             inCol = 2* col;  
    16.             if(inRow >= height) {  
    17.                 inRow = 0;  
    18.             }  
    19.             if(inCol >= width) {  
    20.                 inCol = 0;  
    21.             }  
    22.             float sumRed = 0, sumGreen = 0, sumBlue = 0;  
    23.             for(int subRow = -2; subRow <= 2; subRow++) {  
    24.                 int inRowOff = inRow + subRow;  
    25.                 if(inRowOff >= height || inRowOff < 0) {  
    26.                     inRowOff = 0;  
    27.                 }  
    28.                 for(int subCol = -2; subCol <= 2; subCol++) {  
    29.                     int inColOff = inCol + subCol;  
    30.                     if(inColOff >= width || inColOff < 0) {  
    31.                         inColOff = 0;  
    32.                     }  
    33.                     index = inRowOff * width + inColOff;  
    34.                     ta = (inPixels[index] >> 24) & 0xff;  
    35.                     int red = (inPixels[index] >> 16) & 0xff;  
    36.                     int green = (inPixels[index] >> 8) & 0xff;  
    37.                     int blue = inPixels[index] & 0xff;  
    38.                     sumRed += keneralData[subRow + 2][subCol + 2] * red;  
    39.                     sumGreen += keneralData[subRow + 2][subCol + 2] * green;  
    40.                     sumBlue += keneralData[subRow + 2][subCol + 2] * blue;  
    41.                 }  
    42.             }  
    43.               
    44.             oudex = row * ow + col;  
    45.             outPixels[oudex] = (ta << 24) | (clamp(sumRed) << 16) | (clamp(sumGreen) << 8) | clamp(sumBlue);  
    46.         }  
    47.        }  
    48.        setRGB( dest, 00, ow, oh, outPixels );  
    49.        return dest;  
    50. }  
    金字塔expand实现代码如下:

    1. public BufferedImage pyramidExpand(BufferedImage src) {  
    2.     int width = src.getWidth();  
    3.     int height = src.getHeight();  
    4.     int[] inPixels = new int[width*height];  
    5.     getRGB(src, 00, width, height, inPixels );  
    6.     int ow = 2*width;  
    7.     int oh =2*height;  
    8.     int[] outPixels = new int[ow * oh];  
    9.     int index = 0, outdex = 0, ta = 0;  
    10.     float[][] keneralData = this.getHVGaussianKeneral();  
    11.     BufferedImage dest = createTwiceCompatibleDestImage(src, null);  
    12.     for(int row=0; row<oh; row++) {  
    13.         for(int col=0; col<ow; col++) {  
    14.             float sumRed = 0, sumGreen = 0, sumBlue = 0;  
    15.             for(int subRow = -2; subRow <= 2; subRow++) {  
    16.                 double srcRow = (row + subRow)/2.0;  
    17.                 double j = Math.floor(srcRow);  
    18.                 double t = srcRow - j;   
    19.                 if(t > 0) {  
    20.                     continue;  
    21.                 }  
    22.                 if(srcRow >= height || srcRow < 0) {  
    23.                     srcRow = 0;  
    24.                 }  
    25.                 for(int subCol = -2; subCol <= 2; subCol++) {  
    26.                     double srcColOff = (col + subCol)/2.0;  
    27.                     j = Math.floor(srcColOff);  
    28.                     t = srcColOff - j;  
    29.                     if(t > 0) {  
    30.                         continue;  
    31.                     }  
    32.                     if(srcColOff >= width || srcColOff < 0) {  
    33.                         srcColOff = 0;  
    34.                     }  
    35.                     index = (int)(srcRow * width + srcColOff);  
    36.                     ta = (inPixels[index] >> 24) & 0xff;  
    37.                     int red = (inPixels[index] >> 16) & 0xff;  
    38.                     int green = (inPixels[index] >> 8) & 0xff;  
    39.                     int blue = inPixels[index] & 0xff;  
    40.                     sumRed += keneralData[subRow + 2][subCol + 2] * red;  
    41.                     sumGreen += keneralData[subRow + 2][subCol + 2] * green;  
    42.                     sumBlue += keneralData[subRow + 2][subCol + 2] * blue;  
    43.                 }  
    44.             }  
    45.             outdex = row * ow + col;  
    46.             outPixels[outdex] = (ta << 24) | (clamp(4.0f * sumRed) << 16) | (clamp(4.0f * sumGreen) << 8) | clamp(4.0f * sumBlue);  
    47.             // outPixels[outdex] = (ta << 24) | (clamp(sumRed) << 16) | (clamp(sumGreen) << 8) | clamp(sumBlue);  
    48.         }  
    49.     }  
    50.     setRGB( dest, 00, ow, oh, outPixels );  
    51.     return dest;  
    52. }  
    图像金字塔的reduce与expand过程都是卷积采样实现。特别注意的是expand

    操作不是reduce的可逆操作。

    关于什么是卷积,高斯滤波请参见博客上的其它相关文章。

    高斯金字塔全部算法源代码如下:

    1. package com.gloomyfish.image.pyramid;  
    2.   
    3. import java.awt.image.BufferedImage;  
    4. import java.awt.image.ColorModel;  
    5.   
    6. public class PyramidAlgorithm extends GaussianFilter {  
    7.     private float a;  
    8.   
    9.     public PyramidAlgorithm() {  
    10.         a = 0.4f;  
    11.     }  
    12.       
    13.     public void setParameter(float p) {  
    14.         this.a = p;  
    15.     }  
    16.   
    17.     public BufferedImage[] pyramidDown(BufferedImage src, int level) {  
    18.         BufferedImage[] imagePyramids = new BufferedImage[level + 1];  
    19.         imagePyramids[0] = src;  
    20.         for(int i=1; i<imagePyramids.length; i++) {  
    21.             imagePyramids[i] = pyramidReduce(imagePyramids[i-1]);  
    22.         }  
    23.         return imagePyramids;  
    24.     }  
    25.       
    26.     public BufferedImage[] pyramidUp(BufferedImage[] srcImage) {  
    27.         BufferedImage[] imagePyramids = new BufferedImage[srcImage.length];  
    28.         for(int i=0; i<srcImage.length; i++) {  
    29.             imagePyramids[i] = pyramidExpand(srcImage[i]);  
    30.         }  
    31.         return imagePyramids;  
    32.     }  
    33.       
    34.     /*** 
    35.      * l1 = g1 - expand(g2) 
    36.      * l2 = g2 - expand(g3) 
    37.      * l0 = g0 - expand(g1) 
    38.      * @param reduceImages 
    39.      * @param expandImages 
    40.      * @return 
    41.      */  
    42.     public BufferedImage[] getLaplacianPyramid(BufferedImage[] reduceImages) {  
    43.         BufferedImage[] laplaciImages = new BufferedImage[reduceImages.length -1];  
    44.         for(int i=1; i<reduceImages.length; i++) {  
    45.             BufferedImage expandImage = pyramidExpand(reduceImages[i]);  
    46.             laplaciImages[i-1] = createCompatibleDestImage(expandImage, null);  
    47.             int width = reduceImages[i-1].getWidth();  
    48.             int height = reduceImages[i-1].getHeight();  
    49.               
    50.             int ewidth = expandImage.getWidth();  
    51.             width = (width > ewidth) ? ewidth : width;  
    52.             height = (height > expandImage.getHeight()) ? expandImage.getHeight():height;  
    53.             System.out.println(" width = " + width + " expand width = " + ewidth);  
    54.               
    55.             int[] reducePixels = new int[width*height];  
    56.             int[] expandPixels = new int[width*height];  
    57.             int[] laPixels = new int[width*height];  
    58.             getRGB( reduceImages[i-1], 00, width, height, reducePixels);  
    59.             getRGB( expandImage, 00, width, height, expandPixels );  
    60.             int index = 0;  
    61.             int er = 0, eg = 0, eb = 0;  
    62.             for(int row=0; row<height; row++) {  
    63.                 int ta = 0, tr = 0, tg = 0, tb = 0;  
    64.                 for(int col=0; col<width; col++) {  
    65.                     index = row * width + col;  
    66.                     ta = (reducePixels[index] >> 24) & 0xff;  
    67.                     tr = (reducePixels[index] >> 16) & 0xff;  
    68.                     tg = (reducePixels[index] >> 8) & 0xff;  
    69.                     tb = reducePixels[index] & 0xff;  
    70.                       
    71.                     ta = (expandPixels[index] >> 24) & 0xff;  
    72.                     er = (expandPixels[index] >> 16) & 0xff;  
    73.                     eg = (expandPixels[index] >> 8) & 0xff;  
    74.                     eb = expandPixels[index] & 0xff;  
    75.                       
    76.                     tr = tr - er;  
    77.                     tg = tg - eg;  
    78.                     tb = tb - eb;  
    79.                       
    80.                     laPixels[index] = (ta << 24) | (clamp(tr) << 16) | (clamp(tg) << 8) | clamp(tb);  
    81.                 }  
    82.             }  
    83.             setRGB( laplaciImages[i-1], 00, width, height, laPixels );  
    84.         }  
    85.   
    86.         return laplaciImages;  
    87.     }  
    88.       
    89.     private BufferedImage pyramidReduce(BufferedImage src) {  
    90.         int width = src.getWidth();  
    91.         int height = src.getHeight();  
    92.         BufferedImage dest = createSubCompatibleDestImage(src, null);  
    93.         int[] inPixels = new int[width*height];  
    94.         int ow = width/2;  
    95.         int oh = height/2;  
    96.         int[] outPixels = new int[ow*oh];  
    97.         getRGB(src, 00, width, height, inPixels );  
    98.         int inRow=0, inCol = 0, index = 0, oudex =0, ta = 0;  
    99.         float[][] keneralData = this.getHVGaussianKeneral();  
    100.         for(int row=0; row<oh; row++) {  
    101.             for(int col=0; col<ow; col++) {  
    102.                 inRow = 2* row;  
    103.                 inCol = 2* col;  
    104.                 if(inRow >= height) {  
    105.                     inRow = 0;  
    106.                 }  
    107.                 if(inCol >= width) {  
    108.                     inCol = 0;  
    109.                 }  
    110.                 float sumRed = 0, sumGreen = 0, sumBlue = 0;  
    111.                 for(int subRow = -2; subRow <= 2; subRow++) {  
    112.                     int inRowOff = inRow + subRow;  
    113.                     if(inRowOff >= height || inRowOff < 0) {  
    114.                         inRowOff = 0;  
    115.                     }  
    116.                     for(int subCol = -2; subCol <= 2; subCol++) {  
    117.                         int inColOff = inCol + subCol;  
    118.                         if(inColOff >= width || inColOff < 0) {  
    119.                             inColOff = 0;  
    120.                         }  
    121.                         index = inRowOff * width + inColOff;  
    122.                         ta = (inPixels[index] >> 24) & 0xff;  
    123.                         int red = (inPixels[index] >> 16) & 0xff;  
    124.                         int green = (inPixels[index] >> 8) & 0xff;  
    125.                         int blue = inPixels[index] & 0xff;  
    126.                         sumRed += keneralData[subRow + 2][subCol + 2] * red;  
    127.                         sumGreen += keneralData[subRow + 2][subCol + 2] * green;  
    128.                         sumBlue += keneralData[subRow + 2][subCol + 2] * blue;  
    129.                     }  
    130.                 }  
    131.                   
    132.                 oudex = row * ow + col;  
    133.                 outPixels[oudex] = (ta << 24) | (clamp(sumRed) << 16) | (clamp(sumGreen) << 8) | clamp(sumBlue);  
    134.             }  
    135.         }  
    136.         setRGB( dest, 00, ow, oh, outPixels );  
    137.         return dest;  
    138.     }  
    139.       
    140.     public BufferedImage createSubCompatibleDestImage(BufferedImage src, ColorModel dstCM) {  
    141.         if ( dstCM == null )  
    142.             dstCM = src.getColorModel();  
    143.         return new BufferedImage(dstCM, dstCM.createCompatibleWritableRaster(src.getWidth()/2, src.getHeight()/2), dstCM.isAlphaPremultiplied(), null);  
    144.     }  
    145.       
    146.     public BufferedImage createTwiceCompatibleDestImage(BufferedImage src, ColorModel dstCM) {  
    147.         if ( dstCM == null )  
    148.             dstCM = src.getColorModel();  
    149.         return new BufferedImage(dstCM, dstCM.createCompatibleWritableRaster(src.getWidth()*2, src.getHeight()*2), dstCM.isAlphaPremultiplied(), null);  
    150.     }  
    151.       
    152.     public BufferedImage pyramidExpand(BufferedImage src) {  
    153.         int width = src.getWidth();  
    154.         int height = src.getHeight();  
    155.         int[] inPixels = new int[width*height];  
    156.         getRGB(src, 00, width, height, inPixels );  
    157.         int ow = 2*width;  
    158.         int oh =2*height;  
    159.         int[] outPixels = new int[ow * oh];  
    160.         int index = 0, outdex = 0, ta = 0;  
    161.         float[][] keneralData = this.getHVGaussianKeneral();  
    162.         BufferedImage dest = createTwiceCompatibleDestImage(src, null);  
    163.         for(int row=0; row<oh; row++) {  
    164.             for(int col=0; col<ow; col++) {  
    165.                 float sumRed = 0, sumGreen = 0, sumBlue = 0;  
    166.                 for(int subRow = -2; subRow <= 2; subRow++) {  
    167.                     double srcRow = (row + subRow)/2.0;  
    168.                     double j = Math.floor(srcRow);  
    169.                     double t = srcRow - j;   
    170.                     if(t > 0) {  
    171.                         continue;  
    172.                     }  
    173.                     if(srcRow >= height || srcRow < 0) {  
    174.                         srcRow = 0;  
    175.                     }  
    176.                     for(int subCol = -2; subCol <= 2; subCol++) {  
    177.                         double srcColOff = (col + subCol)/2.0;  
    178.                         j = Math.floor(srcColOff);  
    179.                         t = srcColOff - j;  
    180.                         if(t > 0) {  
    181.                             continue;  
    182.                         }  
    183.                         if(srcColOff >= width || srcColOff < 0) {  
    184.                             srcColOff = 0;  
    185.                         }  
    186.                         index = (int)(srcRow * width + srcColOff);  
    187.                         ta = (inPixels[index] >> 24) & 0xff;  
    188.                         int red = (inPixels[index] >> 16) & 0xff;  
    189.                         int green = (inPixels[index] >> 8) & 0xff;  
    190.                         int blue = inPixels[index] & 0xff;  
    191.                         sumRed += keneralData[subRow + 2][subCol + 2] * red;  
    192.                         sumGreen += keneralData[subRow + 2][subCol + 2] * green;  
    193.                         sumBlue += keneralData[subRow + 2][subCol + 2] * blue;  
    194.                     }  
    195.                 }  
    196.                 outdex = row * ow + col;  
    197.                 outPixels[outdex] = (ta << 24) | (clamp(4.0f * sumRed) << 16) | (clamp(4.0f * sumGreen) << 8) | clamp(4.0f * sumBlue);  
    198.                 // outPixels[outdex] = (ta << 24) | (clamp(sumRed) << 16) | (clamp(sumGreen) << 8) | clamp(sumBlue);  
    199.             }  
    200.         }  
    201.         setRGB( dest, 00, ow, oh, outPixels );  
    202.         return dest;  
    203.     }  
    204.   
    205. }  
    特别注意:我没有处理像素的宽与高,如果宽与高不是偶数可能

    会有问题,使用时请自己处理吧。

    UI实现源代码如下:

    1. package com.gloomyfish.image.pyramid;  
    2.   
    3. import java.awt.BorderLayout;  
    4. import java.awt.Dimension;  
    5. import java.awt.FlowLayout;  
    6. import java.awt.Graphics;  
    7. import java.awt.MediaTracker;  
    8. import java.awt.event.ActionEvent;  
    9. import java.awt.event.ActionListener;  
    10. import java.awt.image.BufferedImage;  
    11. import java.io.File;  
    12. import java.io.IOException;  
    13.   
    14. import javax.imageio.ImageIO;  
    15. import javax.swing.JButton;  
    16. import javax.swing.JComponent;  
    17. import javax.swing.JFileChooser;  
    18. import javax.swing.JFrame;  
    19. import javax.swing.JPanel;  
    20.   
    21. public class PyramidDemoUI extends JComponent implements ActionListener {  
    22.   
    23.     /** 
    24.      *  
    25.      */  
    26.     private static final long serialVersionUID = 1L;  
    27.     private JButton upButton;  
    28.     private JButton downButton;  
    29.     private BufferedImage[] reduceImages;  
    30.     private BufferedImage[] expandImages;  
    31.     private BufferedImage sourceImage;  
    32.     private Dimension mySize;  
    33.     private MediaTracker tracker;  
    34.       
    35.     public PyramidDemoUI(File f)  
    36.     {  
    37.         initComponents(f);  
    38.     }  
    39.   
    40.     private void initComponents(File f)  
    41.     {  
    42.         // TODO Auto-generated method stub  
    43.         try {    
    44.             sourceImage = ImageIO.read(f);    
    45.         } catch (IOException e1) {    
    46.             e1.printStackTrace();    
    47.         }    
    48.             
    49.         tracker = new MediaTracker(this);    
    50.         tracker.addImage(sourceImage, 1);    
    51.             
    52.         // blocked 10 seconds to load the image data    
    53.         try {    
    54.             if (!tracker.waitForID(110000)) {    
    55.                 System.out.println("Load error.");    
    56.                 System.exit(1);    
    57.             }// end if    
    58.         } catch (InterruptedException e) {    
    59.             e.printStackTrace();    
    60.             System.exit(1);    
    61.         }// end catch    
    62.           
    63.         JPanel btnPanel = new JPanel();  
    64.         btnPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));  
    65.         upButton = new JButton("Laplacian Pyramid");  
    66.         downButton = new JButton("Pyramid Down");  
    67.         upButton.addActionListener(this);  
    68.         downButton.addActionListener(this);  
    69.         btnPanel.add(upButton);  
    70.         btnPanel.add(downButton);  
    71.         mySize = new Dimension(800800);     
    72.         JFrame mainFrame = new JFrame("Pyramid Demo - Gloomyfish");  
    73.         mainFrame.getContentPane().setLayout(new BorderLayout());  
    74.         mainFrame.getContentPane().add(this, BorderLayout.CENTER);  
    75.         mainFrame.getContentPane().add(btnPanel, BorderLayout.SOUTH);  
    76.         mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);    
    77.         mainFrame.pack();    
    78.         mainFrame.setVisible(true);    
    79.     }  
    80.   
    81.     @Override  
    82.     public Dimension getPreferredSize() {  
    83.         return mySize;  
    84.     }  
    85.   
    86.     @Override  
    87.     protected void paintComponent(Graphics g)   
    88.     {  
    89. //      g.drawImage(sourceImage, 10, 10, sourceImage.getWidth(), sourceImage.getHeight(), null);  
    90.         int width = 10;  
    91. //      if(reduceImages != null) {  
    92. //          for(int i=1; i<reduceImages.length; i++) {  
    93. //              width += (10 + reduceImages[i-1].getWidth());  
    94. //              g.drawImage(reduceImages[i], width, 10, reduceImages[i].getWidth(), reduceImages[i].getHeight(), null);  
    95. //          }  
    96. //      }  
    97.           
    98.         width = 10;  
    99.         if(expandImages != null) {  
    100.             for(int i=0; i<expandImages.length; i++) {  
    101.                 g.drawImage(expandImages[i], width, 15, expandImages[i].getWidth(), expandImages[i].getHeight(), null);  
    102.                 // g.drawImage(expandImages[i], width, 15 + sourceImage.getHeight(), expandImages[i].getWidth(), expandImages[i].getHeight(), null);  
    103.                 width += (10 + expandImages[i].getWidth());  
    104.             }  
    105.         }  
    106.         super.paintComponent(g);  
    107.     }  
    108.       
    109.     public static void main(String[] args) {    
    110.         JFileChooser chooser = new JFileChooser();    
    111.         chooser.showOpenDialog(null);    
    112.         File f = chooser.getSelectedFile();    
    113.         new PyramidDemoUI(f);    
    114.     }  
    115.   
    116.     @Override  
    117.     public void actionPerformed(ActionEvent event) {  
    118.         if(event.getActionCommand().equals("Laplacian Pyramid")) {  
    119.             if(reduceImages != null) {  
    120.                 // int size = reduceImages.length;  
    121.                 PyramidAlgorithm pyramid = new PyramidAlgorithm();  
    122.                 expandImages = pyramid.getLaplacianPyramid(reduceImages);  
    123.                 // expandImages = pyramid.pyramidUp(reduceImages);  
    124.                 repaint();  
    125.             } else {  
    126.                   
    127.             }  
    128.   
    129.         } else if(event.getActionCommand().equals("Pyramid Down")) {  
    130.             // a.Smooth the image with Gaussian filter 5×5(1/4-a/2, 1/4, a, 1/4, 1/4-a/2) a = [0.3,0.6]  
    131.             // b.Sub sample the image by half - 选择偶数行与列  
    132.             // c.If reached desired size stop, else send the result to step 1  
    133.             PyramidAlgorithm pyramid = new PyramidAlgorithm();  
    134.             reduceImages = pyramid.pyramidDown(sourceImage, 3);  
    135.             repaint();  
    136.         } else {  
    137.             // do nothing  
    138.         }  
    139.           
    140.     }    
    141.   
    142. }  

    版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 相关阅读:
    用Windows自带的命令结束进程
    spoolsv spoolsv.exe 进程信息
    Win XP打印机共享问题解决方法
    解决XP专业版局域网访问故障十八招
    取消时间限制和内存限制
    与操作
    SVN分支和合并的简单例子
    PHPExcel常用方法汇总
    python在windows下的简单搭建
    centos 6.2用yum安装中文输入法
  • 原文地址:https://www.cnblogs.com/mao0504/p/4705502.html
Copyright © 2011-2022 走看看