图像处理------简单数字水印 - 文字轧花效果

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

 

实现原理

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

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

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一个类中.

 

程序效果如下:

 

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

[java] view plaincopy

  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, 0, 0, width, height, inPixels );  
  39.         getRGB( topImage, 0, 0, width, height, outPixels );  
  40.         processonePixelWidth(width, height, inPixels, outPixels, topImage);  
  41.         getRGB( buttomImage, 0, 0, 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, 0, 0, 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, 0, 0, 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, 0, 0, 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( 0, 0, width, height, sinPixels, 0, width );  
  143.         dest.getRGB( 0, 0, 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( 0, 0, dw, dh, dinPixels, 0, dw );  
  166.     }  
  167. }  

程序测试代码如下:

[java] view plaincopy

  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, 0, 0, rawImg.getWidth(), rawImg.getHeight(), null);  
  51.         g2.drawImage(modImg, rawImg.getWidth()+10, 0, 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. }  
时间: 2024-10-04 09:04:43

图像处理------简单数字水印 - 文字轧花效果的相关文章

一个简单但是效果很好的“文字人物”效果

  一个简单但是效果很好的"文字人物"效果!实用粗暴,运用在海报更适合,值得借鉴学习 分类: PS入门教程

jquery实现简单文字提示效果_jquery

本文实例讲述了jquery实现简单文字提示效果.分享给大家供大家参考,具体如下: <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=gb2312" /> <title>jquery实现简单文字提示</title> &l

Flash实现扫描显示文字的效果

本例主要通过几个简单的运动中间帧动画与镂空的文字块来实现扫描显示文字的效果.至于本例的设计思路,可以先参看图1所示的影片图层结构图. 图1 影片图层结构图 1.图中所标示的数字1.2.3.4分别代表了三个图层和舞台本身.也就是说,需要建立用来放置不同对象的三个图层. a)顶层扫描线层:用以放置最右边的首条扫描线. b)镂空文字层:用以放置写有镂空文字的图块. c)扫描线层:用以放置从文字上经过的扫描线. d)底层(舞台):也就是背景. 2. 利用Flash图形层叠覆盖的特性来制作镂空文字色块的方

Flash制作跳动的文字镜像效果

此实例实现的是制作一个跳动的文字镜像效果.效果实现主要有两个方面,一是通过延迟不同元件的动画开播时间,实现了文字的先后运动.二是通过对中间帧动画变速调整,实现了跳动的弹性效果.而效果的主要制作步骤也是有两个,一是制作字符模板,二即是制作具体效果.难点在于元件转换.元件替换.中间帧动画调速和简单的播放控制.最终播放效果如图1所示,要实现这一效果,具体制作过程如下 图1 最终效果 一.制作字符模板 1.新建一个电影,在属性面板中设置其尺寸为550pxX400px,选择一种颜色(本例为#FFCCFF)

在PowerPoint2010中简单制作文字闪烁特效教程

  很显然,需要制作不停闪烁的动画,就得先制作出一个闪烁的动画,然后让它一直重复这个动画即可.当然,这只相当于一个方法简介,在任何版本的PowerPoint中都是行得通的,本教程就为大家介绍在PowerPoint2010中简单制作文字闪烁特效方法,感兴趣的朋友可以参考本文,希望能对大家有所帮助! 方法/步骤 1.在计算机桌面双击PowerPoint2010图标将其打开运行,在启动的PowerPoint2010演示文稿编辑软件窗口,依次点击"文件"-->"新建"

iOS实现知乎和途家导航栏渐变的文字动画效果_IOS

效果图如下 分析如下:      1.导航栏一开始是隐藏的,随着scrollView滚动而渐变      2.导航栏左右两边的navigationItem是一直显示的      3.导航栏参考了途家app,使用了毛玻璃效果,背景是一张图片      4.下拉放大图片效果      5.title文字动画效果 通过简单分析,系统的导航栏实现以上效果有点困难,直接自定义一个假的导航栏更容易点 分布拆解实现以上效果 一.下拉放大header图片 - (void)viewDidLoad { [super

多种JQuery循环滚动文字图片效果代码_jquery

自己模仿JQ插件的写法写了一个循环滚动列表插件,支持自定义上.下.左.右四个方向,支持平滑滚动或者间断滚动两种方式,都是通过参数设置.JQ里面有些重复的地方,暂时没想到更好的方法去精简.不过效果还是可以的,如下(效果图上传后都加速了,实际效果比这个要慢很多):  html代码如下: <!doctype html> <html lang="zh-cn"> <head> <meta charset="utf-8"> <

js焦点文字滚动效果代码分享_javascript技巧

本文实例讲述了js焦点文字滚动效果.分享给大家供大家参考.具体如下:效果描述:今天推荐的这个又是一个原生的js焦点图效果 默认自动切换,也可以手动切换 javascript代码采用函数式对象编程,也就是javascript编程中的Module模式 基本用法很简单,主要特点有三: 1.模块化,可重用 2.封装了变量和function,和全局的命名空间不接触,不污染全局变量 3.只暴露可用public方法,其他私有方法全部隐藏,确保js相互之间不会冲突 运行效果图:-----------------

Illustrator结合photoshop设计可爱碎花风格3D艺术文字插画效果绘制教程

给各位Illustrator软件的使用者们来详细的解析分享一下结合photoshop设计可爱碎花风格3D艺术文字插画效果的绘制教程. 教程分享: 效果图:   第1步 首先,创建一个新文档,大小为1200 x770,并去从#a1dbff#f0f9ff径向渐变填充画布,从黑暗的中心在过渡边缘光 .   Step 2 下载此字体Levenim MT Bold,粗体.加载的字体,然后打开Illustrator中,并键入 ‘MYINKBLOGâ€.   Step 3 在Illustrator中,选择