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. }  

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

  • 相关阅读:
    51nod 1087 1 10 100 1000(找规律+递推+stl)
    51nod 1082 与7无关的数 (打表预处理)
    51 nod 1080 两个数的平方和
    1015 水仙花数(水题)
    51 nod 1003 阶乘后面0的数量
    51nod 1002 数塔取数问题
    51 nod 1001 数组中和等于K的数对
    51 nod 1081 子段求和
    51nod 1134 最长递增子序列 (O(nlogn)算法)
    51nod 1174 区间中最大的数(RMQ)
  • 原文地址:https://www.cnblogs.com/mao0504/p/4705502.html
Copyright © 2011-2022 走看看