图像处理之基于高斯金字塔的图像融合

简介: 图像处理之基于高斯金字塔的图像融合

好久之前,当我第一次看到这个算法时候,我就爱上它了,那个时候我不懂什么是高


斯金字塔,但是我知道埃及有金字塔。一番研究之后,搞懂了什么是图像金字塔于是


我写了一篇文章在我的博客上,可以看这里:


http://blog.csdn.net/jia20003/article/details/9116931


但是金字塔有什么应用呢,可能最广泛的一个应用就是实现图像融合和图像的无缝


拼接于是我决定在研究一番,于是就有了这篇文章。好了不废话了。算法需要三张


图片,两张图片是需要拼接的图片,最后一张是面罩图片,为什么需要后面我会解释


面罩图片就是选取待拼接两张图片的目标边缘部分,多少合适根据需要。Demo演示


我是各占原图的1/2这样省事。


算法大致的步骤可以分为如下几步:


1.对两张待拼接的图片分别生成DOG,关于什么是DOG,怎么生成,如果不知道


一定要看看这里:


2.对面罩图片(mask image)完成高斯金字塔,层数要跟DOG层数相同。


3. 根据面罩图片的权重,拼接两张图片的DOG,生成一个DOG图片


4.用生成的DOG图片与maskimage 金字塔expand生成的图片相加得到每层,把每一次


叠加得到最后输出图片。


基于高斯金字塔图像融合的原理:


懂得高斯金字塔DOG的生成原理都明白,如果把金字塔reduce与expand的结果相减则


得到DOG,而如果把expand结果与DOG结果相加则得到reduce处理后的图像,因为


reduce图像是间隔采样生成原图,而高斯金字塔融合正是巧妙的利用了这点。



关键代码解释:


实现目标图像DOG提取代码如下,默认情况下是三层:

PyramidBlendProcessor pyramid = new PyramidBlendProcessor(image1, image2, maskImage);
BufferedImage[] image1Lapls = pyramid.getLaplacianPyramid(pyramid.pyramidDown(image1));
BufferedImage[] image2Lapls = pyramid.getLaplacianPyramid(pyramid.pyramidDown(image2));
BufferedImage[] maskPyramid = pyramid.pyramidDown(maskImage);

依靠mask权重实现两个目标图像DOG按层融合的代码如下:

  public BufferedImage blendOneImage(BufferedImage image1, BufferedImage image2, BufferedImage maskImage, BufferedImage blendedImage) {
    int width = image1.getWidth();
        int height = image1.getHeight();
 
        if ( blendedImage == null )
          blendedImage = createCompatibleDestImage( maskImage, null );
 
        int[] image1Pixels = new int[width*height];
        int[] image2Pixels = new int[width*height];
        int[] maskPixels = new int[width*height];
        int[] outPixels = new int[width*height];
        getRGB( image1, 0, 0, width, height, image1Pixels );
        getRGB( image2, 0, 0, width, height, image2Pixels );
        getRGB( maskImage, 0, 0, width, height, maskPixels );
        int index = 0;
        float mr = 0, mg = 0, mb = 0;
        for(int row=0; row<height; row++) {
          int ta1 = 0, tr1 = 0, tg1 = 0, tb1 = 0;
          int ta2 = 0, tr2 = 0, tg2 = 0, tb2 = 0;
          int ta3 = 0, tr3 = 0, tg3 = 0, tb3 = 0;
          for(int col=0; col<width; col++) {
            index = row * width + col;
            ta1 = (image1Pixels[index] >> 24) & 0xff;
                tr1 = (image1Pixels[index] >> 16) & 0xff;
                tg1 = (image1Pixels[index] >> 8) & 0xff;
                tb1 = image1Pixels[index] & 0xff;
                
            ta2 = (image2Pixels[index] >> 24) & 0xff;
                tr2 = (image2Pixels[index] >> 16) & 0xff;
                tg2 = (image2Pixels[index] >> 8) & 0xff;
                tb2 = image2Pixels[index] & 0xff;
                
            ta3 = (maskPixels[index] >> 24) & 0xff;
                tr3 = (maskPixels[index] >> 16) & 0xff;
                tg3 = (maskPixels[index] >> 8) & 0xff;
                tb3 = maskPixels[index] & 0xff;
                
                mr = tr3 / 255.0f;
                mg = tg3 / 255.0f;
                mb = tb3 / 255.0f;
                int br = (int)(mr * tr2  +  (1.0f - mr) * tr1);
                int bg = (int)(mg * tg2  +  (1.0f - mr) * tg1);
                int bb = (int)(mb * tb2  +  (1.0f - mr) * tb1);
                outPixels[index] = (ta1 << 24) | (clamp(br) << 16) | (clamp(bg) << 8) | clamp(bb);
          }
        }
        setRGB( blendedImage, 0, 0, width, height, outPixels );
        return blendedImage;
  }

合并DOG融合每层图片与mask expand之后的代码如下:

    BufferedImage[] image1Lapls = this.pyramidUp(this.pyramidDown(maskImg));
    BufferedImage result = null;
    int size = blendResults.length;
    for(int i=size - 1; i>=0; i--)
    {
      if((i-1) < 0){
        result = this.collapse(image1Lapls[i], blendResults[i]);
      } else {
        image1Lapls[i-1] = this.pyramidExpand(this.collapse(image1Lapls[i], blendResults[i]), image1Lapls[i-1].getWidth(), image1Lapls[i-1].getHeight()); 
      }
    }
    // return image1Lapls[0];
    return result;

图片一:

图片二:

mask图片:一半是黑色一半是白色

最终效果如下:

完全源代码:

package com.gloomyfish.image.pyramid.blend;
 
import java.awt.image.BufferedImage;
 
import com.gloomyfish.image.pyramid.PyramidAlgorithm;
 
 
public class PyramidBlendProcessor extends PyramidAlgorithm
{
  BufferedImage image1;
  BufferedImage image2; 
  BufferedImage maskImg;  
  public PyramidBlendProcessor(BufferedImage image1, BufferedImage image2, BufferedImage maskImage)
  {
    this.image1 = image1;
    this.image2 = image2;
    this.maskImg = createMaskImage(image1, image2, maskImage);
  }
  
  public BufferedImage mergeMaskWithResult(BufferedImage[] blendResults)
  {
    BufferedImage[] image1Lapls = this.pyramidUp(this.pyramidDown(maskImg));
    BufferedImage result = null;
    int size = blendResults.length;
    for(int i=size - 1; i>=0; i--)
    {
      if((i-1) < 0){
        result = this.collapse(image1Lapls[i], blendResults[i]);
      } else {
        image1Lapls[i-1] = this.pyramidExpand(this.collapse(image1Lapls[i], blendResults[i]), image1Lapls[i-1].getWidth(), image1Lapls[i-1].getHeight()); 
      }
    }
    // return image1Lapls[0];
    return result;
  }
  
  private BufferedImage createMaskImage(BufferedImage image12,
      BufferedImage image22, BufferedImage maskImage) {
    int width = image1.getWidth();
        int height = image1.getHeight();
        BufferedImage realMaskImg = createCompatibleDestImage( image1, null );
 
        int[] image1Pixels = new int[width*height];
        int[] image2Pixels = new int[width*height];
        int[] maskPixels = new int[width*height];
        int[] outPixels = new int[width*height];
        getRGB( image1, 0, 0, width, height, image1Pixels );
        getRGB( image2, 0, 0, width, height, image2Pixels );
        getRGB( maskImage, 0, 0, width, height, maskPixels );
        int index = 0;
        for(int row=0; row<height; row++) {
          int ta1 = 0, tr1 = 0, tg1 = 0, tb1 = 0;
          int ta2 = 0, tr2 = 0, tg2 = 0, tb2 = 0;
          int ma = 0, mr = 0, mg = 0, mb = 0;
          for(int col=0; col<width; col++) {
            index = row * width + col;
            ta1 = (image1Pixels[index] >> 24) & 0xff;
                tr1 = (image1Pixels[index] >> 16) & 0xff;
                tg1 = (image1Pixels[index] >> 8) & 0xff;
                tb1 = image1Pixels[index] & 0xff;
                
            ta2 = (image2Pixels[index] >> 24) & 0xff;
                tr2 = (image2Pixels[index] >> 16) & 0xff;
                tg2 = (image2Pixels[index] >> 8) & 0xff;
                tb2 = image2Pixels[index] & 0xff;
                
            ma = (maskPixels[index] >> 24) & 0xff;
                mr = (maskPixels[index] >> 16) & 0xff;
                mg = (maskPixels[index] >> 8) & 0xff;
                mb = maskPixels[index] & 0xff;
                if(mr < 127) {
                  outPixels[index] = (ta1 << 24) | (tr1 << 16) | (tg1 << 8) | tb1;
                } else if(mr >=127) {
                  outPixels[index] = (ta2 << 24) | (tr2 << 16) | (tg2 << 8) | tb2;
                } else {
                  //outPixels[index] = (ta2 << 24) | (mr << 16) | (mg << 8) | mb;
                }
                   
          }
        }
        setRGB( realMaskImg, 0, 0, width, height, outPixels );
        return realMaskImg;
  }
}

PyramidAlgorithm代码参见这里:

http://blog.csdn.net/jia20003/article/details/9116931

UI部分的代码如下:

package com.gloomyfish.image.pyramid.blend;
 
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
 
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
 
public class MainUI extends JComponent implements ActionListener {
 
  /**
   * 
   */
  private JButton blendBtn;
  private Dimension mySize;
  private BufferedImage resultImage;
  private BufferedImage maskImage;
  private BufferedImage image1;
  private BufferedImage image2;
  
  private static final long serialVersionUID = 1L;
  
  public MainUI(BufferedImage image1, BufferedImage image2, BufferedImage maskImage)
  {
        JPanel btnPanel = new JPanel();
        btnPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
        blendBtn = new JButton("Pyramid Blend");
        blendBtn.addActionListener(this);
        btnPanel.add(blendBtn);
        mySize = new Dimension(600, 600);
        this.image1 = image1;
        this.image2 = image2;
        this.maskImage = maskImage;
        JFrame mainFrame = new JFrame("Pyramid Blend Demo - Gloomyfish");
        mainFrame.getContentPane().setLayout(new BorderLayout());
        mainFrame.getContentPane().add(this, BorderLayout.CENTER);
        mainFrame.getContentPane().add(btnPanel, BorderLayout.SOUTH);
        mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  
        mainFrame.pack();  
        mainFrame.setVisible(true);  
  }
  
  @Override
  public Dimension getPreferredSize() {
    return mySize;
  }
 
  @Override
  public void actionPerformed(ActionEvent e) {
    // get two DOG image
    PyramidBlendProcessor pyramid = new PyramidBlendProcessor(image1, image2, maskImage, 4);
    
    BufferedImage[] image1Lapls = pyramid.getLaplacianPyramid(pyramid.pyramidDown(image1));
    BufferedImage[] image2Lapls = pyramid.getLaplacianPyramid(pyramid.pyramidDown(image2));
    BufferedImage[] maskPyramid = pyramid.pyramidDown(maskImage);
    maskPyramid = pyramid.pyramidUp(maskPyramid);
    System.out.println("End first step......");
    // get mask pyramid
    
    // blend them by level from top to bottom
    BufferedImage[] blendImages = new BufferedImage[image1Lapls.length];
    for(int i=0; i<blendImages.length; i++)
    {
      blendImages[i] = pyramid.blendOneImage(image1Lapls[i], image2Lapls[i], maskPyramid[i], null);     
    }
    
    // collapse them
//    BufferedImage[] cImages = new BufferedImage[blendImage.length-1];
//    for(int i=(blendImage.length-1); i>0; i--)
//    {
//      BufferedImage destImage = pyramid.pyramidExpand(blendImage[i], blendImage[i-1].getWidth(),  blendImage[i-1].getHeight());
//      cImages[i-1] = pyramid.collapse(destImage, blendImage[i-1]);
//    }
//    resultImage = cImages[0];
    resultImage = pyramid.mergeMaskWithResult(blendImages);
//    for(int i=cImages.length - 1; i>0; i--) 
//    {
//      BufferedImage destImage = pyramid.pyramidExpand(cImages[i], cImages[i-1].getWidth(),  cImages[i-1].getHeight());
//      resultImage = pyramid.collapse(destImage, cImages[i-1]);
//    }
    repaint();
  }
 
  @Override
  protected void paintComponent(Graphics g) {
    if(resultImage != null)
    {
      g.drawImage(resultImage, 10, 10, resultImage.getWidth(), resultImage.getHeight(), null);
    }
    super.paintComponent(g);
  }
  
    public static void main(String[] args) { 
      
    try {
      File f2 = new File("D:\\resource\\orange.jpg");
      File f1 = new File("D:\\resource\\apple.jpg");
      File f3 = new File("D:\\resource\\mask512.jpg");
      BufferedImage image1 = ImageIO.read(f1);
      BufferedImage image2 = ImageIO.read(f2); 
      BufferedImage maskImg = ImageIO.read(f3); 
      new MainUI(image1, image2, maskImg);  
        } catch (IOException e1) {  
            e1.printStackTrace();  
        }  
    }
  
 
}

代码写的比较乱,做的时候就是希望快点看到效果,可读性不是很好,可能需要

整一下代码,但是内容绝对值得一读,希望得到大家的支持。

层数越多,融合效果越好,当然计算时间也越长!

转载请务必注明,谢谢!

相关文章
|
1月前
|
机器学习/深度学习 算法
低光图像增强
这篇摘要讨论了低光照图像增强技术,涉及HDRNet、GAN、轻量化伪影、语义分割网络和Retinex等方法。核心任务是提升图像亮度和细节。方法包括分布映射(如伽马矫正、直方图均衡化)、模型优化(Retinex理论)和深度学习(亮度增强与噪声去除)。传统方法不依赖数据,但可能产生伪影;深度学习方法需大量训练数据,无监督学习更优。不足之处在于缺乏成对数据集和精确标签。
67 1
|
1月前
halcon的灰度变换(图像增强)
halcon的灰度变换(图像增强)
144 1
|
21天前
|
资源调度 计算机视觉
图像处理之图像加噪
图像处理之图像加噪
7 0
图像处理之图像加噪
|
20天前
|
算法 计算机视觉
图像处理之USM锐化
图像处理之USM锐化
8 0
|
21天前
|
计算机视觉
图像处理之直方图均衡化
图像处理之直方图均衡化
11 0
|
9月前
|
机器学习/深度学习 传感器 算法
【图像处理】使用各向异性滤波器和分割图像处理从MRI图像检测脑肿瘤(Matlab代码实现)
【图像处理】使用各向异性滤波器和分割图像处理从MRI图像检测脑肿瘤(Matlab代码实现)
|
10月前
|
算法
水下图像融合增强(Matlab代码实现)
水下图像融合增强(Matlab代码实现)
177 0
|
算法 计算机视觉
图像增强—图像锐化
图像增强—图像锐化
图像增强—图像锐化
|
机器学习/深度学习 传感器 算法
【图像融合】基于NSST结合PCNN实现医学多模态图像融合附matlab代码
【图像融合】基于NSST结合PCNN实现医学多模态图像融合附matlab代码
|
机器学习/深度学习 传感器 编解码
【图像融合】基于小波变换实现高分辨率全色图图像融合(含评价指标)附matlab代码
【图像融合】基于小波变换实现高分辨率全色图图像融合(含评价指标)附matlab代码