zoukankan      html  css  js  c++  java
  • 图像处理------简单数字水印

    首先看一下效果,左边是一张黑白的文字图像,右边是混合之后的数字水印效果

     

    实现原理

    主要是利用位图块迁移算法,首先提取文字骨架,宽度为一个像素。然后将提取的骨架,按

    照一定的像素值填充到目标图像中即可。关于位图块迁移算法说明请看这里:

    http://en.wikipedia.org/wiki/Bit_blit

     

    程序思路:

    1.      首先创建两张白板的单色位图,读入黑白文字图片,

    2.      移动一个像素位开始读取文字图片中的像素,将每个对应像素与白板单色图片叠加,直

    至黑白文字图片完全copy到单色白板中。

    3.      重复上面操作,唯一不同的,将白板像素移动一个像素为,以后开始填充

    4.      分别将两张位图块迁移图片与原黑白文字图片像素完成一个或操作,则得到左上和右下

    的文字骨架。

    5.      将两个文字骨架的像素填充到目标彩色图片中,即得到轧花效果的图片

    根据输入参数不同,还可得到雕刻效果图片。

     

    关键代码解释:

     

    实现位图块迁移算法的代码如下:

    // one pixel transfer

    for(int row=1; row<height; row++) {

        int ta = 0, tr = 0, tg = 0, tb = 0;

        for(int col=1; col<width; col++) {

           index = row * width + col;

           index2 = (row-1) * width + (col-1);

           ta = (inPixels[isTop?index:index2] >> 24) & 0xff;

            tr = (inPixels[isTop?index:index2] >> 16) & 0xff;

            tg = (inPixels[isTop?index:index2] >> 8) & 0xff;

            tb = inPixels[isTop?index:index2] & 0xff;

            outPixels[isTop?index2:index] = (ta << 24) | (tr<< 16) | (tg << 8) | tb;

        }

    }

    布尔变量isTop决定是否填充单色白板位移(Offset)是零还是一。

     

    获取一个像素宽度骨架的方法为processonePixelWidth()主要是利用文字图片是一个二值图像,

    从而remove掉多余的像素。

     

    混合轧花的方法为embossImage()主要是简单的像素填充,布尔变量主要是用来控制是凹轧花

    还是凸轧花效果。所有对文字图像的处理和轧花效果的处理封装在BitBltFilter一个类中.

     

    程序效果如下:

     

    位图块位移算法实现完全源代码如下:

    1. package com.gloomyfish.zoom.study;  
    2.   
    3. import java.awt.image.BufferedImage;  
    4.   
    5. import com.process.blur.study.AbstractBufferedImageOp;  
    6.   
    7. public class BitBltFilter extends AbstractBufferedImageOp {  
    8.     // raster operation - bit block transfer.  
    9.     // 1975 for the Smalltalk-72 system, For the Smalltalk-74 system  
    10.     private boolean isTop = true;  
    11.   
    12.     /** 
    13.      * left - top skeleton or right - bottom. 
    14.      *  
    15.      * @param isTop 
    16.      */  
    17.     public void setTop(boolean isTop) {  
    18.         this.isTop = isTop;  
    19.     }  
    20.       
    21.     /** 
    22.      * blend the pixels and get the final output image 
    23.      *  
    24.      * @param textImage 
    25.      * @param targetImage 
    26.      */  
    27.     public void emboss(BufferedImage textImage, BufferedImage targetImage) {  
    28.         // BitBltFilter filter = new BitBltFilter();  
    29.         BufferedImage topImage = filter(textImage, null);  
    30.         setTop(false);  
    31.         BufferedImage buttomImage = filter(textImage, null);  
    32.   
    33.         int width = textImage.getWidth();  
    34.         int height = textImage.getHeight();  
    35.           
    36.         int[] inPixels = new int[width*height];  
    37.         int[] outPixels = new int[width*height];  
    38.         getRGB( textImage, 00, width, height, inPixels );  
    39.         getRGB( topImage, 00, width, height, outPixels );  
    40.         processonePixelWidth(width, height, inPixels, outPixels, topImage);  
    41.         getRGB( buttomImage, 00, width, height, outPixels );  
    42.         processonePixelWidth(width, height, inPixels, outPixels, buttomImage);  
    43.           
    44.         // emboss now  
    45.         embossImage(topImage, targetImage, true);  
    46.         embossImage(buttomImage, targetImage, false);  
    47.     }  
    48.   
    49.     @Override  
    50.     public BufferedImage filter(BufferedImage src, BufferedImage dest) {  
    51.         int width = src.getWidth();  
    52.         int height = src.getHeight();  
    53.   
    54.         if ( dest == null )  
    55.             dest = createCompatibleDestImage(src, null);  
    56.   
    57.         int[] inPixels = new int[width*height];  
    58.         int[] outPixels = new int[width*height];  
    59.         getRGB( src, 00, width, height, inPixels );  
    60.         int index = 0;  
    61.         int index2 = 0;  
    62.         // initialization outPixels  
    63.         for(int row=0; row<height; row++) {  
    64.             for(int col=0; col<width; col++) {  
    65.                 index = row * width + col;  
    66.                 outPixels[index] = (255 << 24) | (255 << 16) | (255 << 8) | 255;  
    67.             }  
    68.         }  
    69.           
    70.         // one pixel transfer  
    71.         for(int row=1; row<height; row++) {  
    72.             int ta = 0, tr = 0, tg = 0, tb = 0;  
    73.             for(int col=1; col<width; col++) {  
    74.                 index = row * width + col;  
    75.                 index2 = (row-1) * width + (col-1);  
    76.                 ta = (inPixels[isTop?index:index2] >> 24) & 0xff;  
    77.                 tr = (inPixels[isTop?index:index2] >> 16) & 0xff;  
    78.                 tg = (inPixels[isTop?index:index2] >> 8) & 0xff;  
    79.                 tb = inPixels[isTop?index:index2] & 0xff;  
    80.                 outPixels[isTop?index2:index] = (ta << 24) | (tr << 16) | (tg << 8) | tb;  
    81.             }  
    82.         }  
    83.         setRGB( dest, 00, width, height, outPixels );  
    84.         return dest;  
    85.     }  
    86.       
    87.     /** 
    88.      *  
    89.      * @param width 
    90.      * @param height 
    91.      * @param inPixels 
    92.      * @param outPixels 
    93.      * @param destImage 
    94.      */  
    95.     private void processonePixelWidth(int width, int height, int[] inPixels, int[] outPixels, BufferedImage destImage) {  
    96.         // now get one pixel data  
    97.         int index = 0;  
    98.         for(int row=0; row<height; row++) {  
    99.             int ta = 0, tr = 0, tg = 0, tb = 0;  
    100.             int ta2 =0, tr2 = 0, tg2 = 0, tb2 = 0;  
    101.             for(int col=0; col<width; col++) {  
    102.                 index = row * width + col;  
    103.                 ta = (inPixels[index] >> 24) & 0xff;  
    104.                 tr = (inPixels[index] >> 16) & 0xff;  
    105.                 tg = (inPixels[index] >> 8) & 0xff;  
    106.                 tb = inPixels[index] & 0xff;  
    107.                   
    108.                 ta2 = (outPixels[index] >> 24) & 0xff;  
    109.                 tr2 = (outPixels[index] >> 16) & 0xff;  
    110.                 tg2 = (outPixels[index] >> 8) & 0xff;  
    111.                 tb2 = outPixels[index] & 0xff;  
    112.                   
    113.                 if(tr2 == tr && tg == tg2 && tb == tb2) {  
    114.                     outPixels[index] = (255 << 24) | (255 << 16) | (255 << 8) | 255;  
    115.                 } else {  
    116.                     if(tr2 < 5 && tg2 < 5 && tb2 < 5) {  
    117.                         outPixels[index] = (ta2 << 24) | (tr2 << 16) | (tg2 << 8) | tb2;  
    118.                     } else {  
    119.                         outPixels[index] = (255 << 24) | (255 << 16) | (255 << 8) | 255;  
    120.                     }  
    121.                 }  
    122.             }  
    123.         }  
    124.         setRGB( destImage, 00, width, height, outPixels );  
    125.     }  
    126.       
    127.     /** 
    128.      *  
    129.      * @param src 
    130.      * @param dest 
    131.      * @param colorInverse - must be setted here!!! 
    132.      */  
    133.     private void embossImage(BufferedImage src, BufferedImage dest, boolean colorInverse)  
    134.     {  
    135.         int width = src.getWidth();  
    136.         int height = src.getHeight();  
    137.         int dw = dest.getWidth();  
    138.         int dh = dest.getHeight();  
    139.           
    140.         int[] sinPixels = new int[width*height];  
    141.         int[] dinPixels = new int[dw*dh];  
    142.         src.getRGB( 00, width, height, sinPixels, 0, width );  
    143.         dest.getRGB( 00, dw, dh, dinPixels, 0, dw );  
    144.         int index = 0;  
    145.         int index2 = 0;  
    146.         for ( int y = 0; y < height; y++ ) {  
    147.             for ( int x = 0; x < width; x++ ) {  
    148.                 index = y * width + x;  
    149.                 int srgb = sinPixels[index];  
    150.                 int r1 = (srgb >> 16) & 0xff;  
    151.                 int g1 = (srgb >> 8) & 0xff;  
    152.                 int b1 = srgb & 0xff;  
    153.                 if(r1 > 200 || g1 >=200 || b1 >=200) {  
    154.                     continue;  
    155.                 }  
    156.                 index2 = y * dw + x;  
    157.                 if(colorInverse) {  
    158.                     r1 = 255 - r1;  
    159.                     g1 = 255 - g1;  
    160.                     b1 = 255 - b1;  
    161.                 }  
    162.                 dinPixels[index2] = (255 << 24) | (r1 << 16) | (g1 << 8) | b1;  
    163.             }  
    164.         }  
    165.         dest.setRGB( 00, dw, dh, dinPixels, 0, dw );  
    166.     }  
    167. }  

    程序测试代码如下:

    1. package com.gloomyfish.zoom.study;  
    2.   
    3. import java.awt.BorderLayout;  
    4. import java.awt.Dimension;  
    5. import java.awt.Graphics;  
    6. import java.awt.Graphics2D;  
    7. import java.awt.image.BufferedImage;  
    8. import java.io.File;  
    9. import java.io.IOException;  
    10.   
    11. import javax.imageio.ImageIO;  
    12. import javax.swing.JComponent;  
    13. import javax.swing.JFileChooser;  
    14. import javax.swing.JFrame;  
    15.   
    16.   
    17. public class BitBltFilterTest extends JComponent {  
    18.     /** 
    19.      *  
    20.      */  
    21.     private static final long serialVersionUID = 7462704254856439832L;  
    22.     private BufferedImage rawImg;  
    23.     private BufferedImage modImg;  
    24.     private Dimension mySize;  
    25.     public BitBltFilterTest(File f) {  
    26.         try {  
    27.             rawImg = ImageIO.read(f);  
    28.             modImg = ImageIO.read(new File("D:\resource\geanmm.png"));  
    29.             // modImg = ImageIO.read(new File("D:\resource\gloomyfish.png"));  
    30.         } catch (IOException e) {  
    31.             e.printStackTrace();  
    32.         }  
    33.         mySize = new Dimension(2*modImg.getWidth() + 20, modImg.getHeight()+ 100);  
    34.         filterImage();  
    35.         final JFrame imageFrame = new JFrame("Emboss Text - gloomyfish");  
    36.         imageFrame.getContentPane().setLayout(new BorderLayout());  
    37.         imageFrame.getContentPane().add(this, BorderLayout.CENTER);  
    38.         imageFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  
    39.         imageFrame.pack();  
    40.         imageFrame.setVisible(true);  
    41.     }  
    42.       
    43.     private void filterImage() {  
    44.         BitBltFilter filter = new BitBltFilter();  
    45.         filter.emboss(rawImg, modImg);  
    46.     }  
    47.       
    48.     public void paint(Graphics g) {  
    49.         Graphics2D g2 = (Graphics2D) g;  
    50.         g2.drawImage(rawImg, 00, rawImg.getWidth(), rawImg.getHeight(), null);  
    51.         g2.drawImage(modImg, rawImg.getWidth()+100, modImg.getWidth(), modImg.getHeight(), null);  
    52.         g2.drawString("text image", rawImg.getWidth()/2, rawImg.getHeight()+10);  
    53.         g2.drawString("sharped text in image", modImg.getWidth() + 10, modImg.getHeight()+10);  
    54.     }  
    55.     public Dimension getPreferredSize() {  
    56.         return mySize;  
    57.     }  
    58.       
    59.     public Dimension getMinimumSize() {  
    60.         return mySize;  
    61.     }  
    62.       
    63.     public Dimension getMaximumSize() {  
    64.         return mySize;  
    65.     }  
    66.       
    67.     public static void main(String[] args) {  
    68.         JFileChooser chooser = new JFileChooser();  
    69.         chooser.showOpenDialog(null);  
    70.         File f = chooser.getSelectedFile();  
    71.         new BitBltFilterTest(f);  
    72.     }  
    73. }  

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

  • 相关阅读:
    JS自定义功能函数实现动态添加网址参数修改网址参数值
    伍、ajax
    类的静态方法(函数)中为什么不能调用非静态成员(属性)?
    android 数据存储 SharePreferences 简单使用
    实现多线程的方式
    线程、进程概念与Android系统组件的关系
    通知—Notifications
    活动栏—Action Bar
    Android菜单—Menu
    对话框控件—Dialog
  • 原文地址:https://www.cnblogs.com/mao0504/p/4706370.html
Copyright © 2011-2022 走看看