天天看點

圖像處理------簡單數字水印 - 文字軋花效果

首先看一下效果,左邊是一張黑白的文字圖像,右邊是混合之後的數字水印效果

圖像處理------簡單數字水印 - 文字軋花效果

實作原理

主要是利用位圖塊遷移算法,首先提取文字骨架,寬度為一個像素。然後将提取的骨架,按

照一定的像素值填充到目标圖像中即可。關于位圖塊遷移算法說明請看這裡:

<a target="_blank" href="http://en.wikipedia.org/wiki/bit_blit">http://en.wikipedia.org/wiki/bit_blit</a>

程式思路:

1.      首先建立兩張白闆的單色位圖,讀入黑白文字圖檔,

2.      移動一個像素位開始讀取文字圖檔中的像素,将每個對應像素與白闆單色圖檔疊加,直

至黑白文字圖檔完全copy到單色白闆中。

3.      重複上面操作,唯一不同的,将白闆像素移動一個像素為,以後開始填充

4.      分别将兩張位圖塊遷移圖檔與原黑白文字圖檔像素完成一個或操作,則得到左上和右下

的文字骨架。

5.      将兩個文字骨架的像素填充到目标彩色圖檔中,即得到軋花效果的圖檔

根據輸入參數不同,還可得到雕刻效果圖檔。

關鍵代碼解釋:

實作位圖塊遷移算法的代碼如下:

// one pixel transfer

for(int row=1; row&lt;height; row++) {

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

    for(int col=1; col&lt;width; col++) {

       index = row * width + col;

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

       ta = (inpixels[istop?index:index2] &gt;&gt; 24) &amp; 0xff;

        tr = (inpixels[istop?index:index2] &gt;&gt; 16) &amp; 0xff;

        tg = (inpixels[istop?index:index2] &gt;&gt; 8) &amp; 0xff;

        tb = inpixels[istop?index:index2] &amp; 0xff;

        outpixels[istop?index2:index] = (ta &lt;&lt; 24) | (tr&lt;&lt; 16) | (tg &lt;&lt; 8) | tb;

    }

}

布爾變量istop決定是否填充單色白闆位移(offset)是零還是一。

擷取一個像素寬度骨架的方法為processonepixelwidth()主要是利用文字圖檔是一個二值圖像,

進而remove掉多餘的像素。

混合軋花的方法為embossimage()主要是簡單的像素填充,布爾變量主要是用來控制是凹軋花

還是凸軋花效果。所有對文字圖像的處理和軋花效果的處理封裝在bitbltfilter一個類中.

程式效果如下:

圖像處理------簡單數字水印 - 文字軋花效果

位圖塊位移算法實作完全源代碼如下:

package com.gloomyfish.zoom.study;  

import java.awt.image.bufferedimage;  

import com.process.blur.study.abstractbufferedimageop;  

public class bitbltfilter extends abstractbufferedimageop {  

    // raster operation - bit block transfer.  

    // 1975 for the smalltalk-72 system, for the smalltalk-74 system  

    private boolean istop = true;  

    /** 

     * left - top skeleton or right - bottom. 

     *  

     * @param istop 

     */  

    public void settop(boolean istop) {  

        this.istop = istop;  

    }  

     * blend the pixels and get the final output image 

     * @param textimage 

     * @param targetimage 

    public void emboss(bufferedimage textimage, bufferedimage targetimage) {  

        // bitbltfilter filter = new bitbltfilter();  

        bufferedimage topimage = filter(textimage, null);  

        settop(false);  

        bufferedimage buttomimage = filter(textimage, null);  

        int width = textimage.getwidth();  

        int height = textimage.getheight();  

        int[] inpixels = new int[width*height];  

        int[] outpixels = new int[width*height];  

        getrgb( textimage, 0, 0, width, height, inpixels );  

        getrgb( topimage, 0, 0, width, height, outpixels );  

        processonepixelwidth(width, height, inpixels, outpixels, topimage);  

        getrgb( buttomimage, 0, 0, width, height, outpixels );  

        processonepixelwidth(width, height, inpixels, outpixels, buttomimage);  

        // emboss now  

        embossimage(topimage, targetimage, true);  

        embossimage(buttomimage, targetimage, false);  

    @override  

    public bufferedimage filter(bufferedimage src, bufferedimage dest) {  

        int width = src.getwidth();  

        int height = src.getheight();  

        if ( dest == null )  

            dest = createcompatibledestimage(src, null);  

        getrgb( src, 0, 0, width, height, inpixels );  

        int index = 0;  

        int index2 = 0;  

        // initialization outpixels  

        for(int row=0; row&lt;height; row++) {  

            for(int col=0; col&lt;width; col++) {  

                index = row * width + col;  

                outpixels[index] = (255 &lt;&lt; 24) | (255 &lt;&lt; 16) | (255 &lt;&lt; 8) | 255;  

            }  

        }  

        // one pixel transfer  

        for(int row=1; row&lt;height; row++) {  

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

            for(int col=1; col&lt;width; col++) {  

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

                ta = (inpixels[istop?index:index2] &gt;&gt; 24) &amp; 0xff;  

                tr = (inpixels[istop?index:index2] &gt;&gt; 16) &amp; 0xff;  

                tg = (inpixels[istop?index:index2] &gt;&gt; 8) &amp; 0xff;  

                tb = inpixels[istop?index:index2] &amp; 0xff;  

                outpixels[istop?index2:index] = (ta &lt;&lt; 24) | (tr &lt;&lt; 16) | (tg &lt;&lt; 8) | tb;  

        setrgb( dest, 0, 0, width, height, outpixels );  

        return dest;  

     * @param width 

     * @param height 

     * @param inpixels 

     * @param outpixels 

     * @param destimage 

    private void processonepixelwidth(int width, int height, int[] inpixels, int[] outpixels, bufferedimage destimage) {  

        // now get one pixel data  

            int ta2 =0, tr2 = 0, tg2 = 0, tb2 = 0;  

                ta = (inpixels[index] &gt;&gt; 24) &amp; 0xff;  

                tr = (inpixels[index] &gt;&gt; 16) &amp; 0xff;  

                tg = (inpixels[index] &gt;&gt; 8) &amp; 0xff;  

                tb = inpixels[index] &amp; 0xff;  

                ta2 = (outpixels[index] &gt;&gt; 24) &amp; 0xff;  

                tr2 = (outpixels[index] &gt;&gt; 16) &amp; 0xff;  

                tg2 = (outpixels[index] &gt;&gt; 8) &amp; 0xff;  

                tb2 = outpixels[index] &amp; 0xff;  

                if(tr2 == tr &amp;&amp; tg == tg2 &amp;&amp; tb == tb2) {  

                    outpixels[index] = (255 &lt;&lt; 24) | (255 &lt;&lt; 16) | (255 &lt;&lt; 8) | 255;  

                } else {  

                    if(tr2 &lt; 5 &amp;&amp; tg2 &lt; 5 &amp;&amp; tb2 &lt; 5) {  

                        outpixels[index] = (ta2 &lt;&lt; 24) | (tr2 &lt;&lt; 16) | (tg2 &lt;&lt; 8) | tb2;  

                    } else {  

                        outpixels[index] = (255 &lt;&lt; 24) | (255 &lt;&lt; 16) | (255 &lt;&lt; 8) | 255;  

                    }  

                }  

        setrgb( destimage, 0, 0, width, height, outpixels );  

     * @param src 

     * @param dest 

     * @param colorinverse - must be setted here!!! 

    private void embossimage(bufferedimage src, bufferedimage dest, boolean colorinverse)  

    {  

        int dw = dest.getwidth();  

        int dh = dest.getheight();  

        int[] sinpixels = new int[width*height];  

        int[] dinpixels = new int[dw*dh];  

        src.getrgb( 0, 0, width, height, sinpixels, 0, width );  

        dest.getrgb( 0, 0, dw, dh, dinpixels, 0, dw );  

        for ( int y = 0; y &lt; height; y++ ) {  

            for ( int x = 0; x &lt; width; x++ ) {  

                index = y * width + x;  

                int srgb = sinpixels[index];  

                int r1 = (srgb &gt;&gt; 16) &amp; 0xff;  

                int g1 = (srgb &gt;&gt; 8) &amp; 0xff;  

                int b1 = srgb &amp; 0xff;  

                if(r1 &gt; 200 || g1 &gt;=200 || b1 &gt;=200) {  

                    continue;  

                index2 = y * dw + x;  

                if(colorinverse) {  

                    r1 = 255 - r1;  

                    g1 = 255 - g1;  

                    b1 = 255 - b1;  

                dinpixels[index2] = (255 &lt;&lt; 24) | (r1 &lt;&lt; 16) | (g1 &lt;&lt; 8) | b1;  

        dest.setrgb( 0, 0, dw, dh, dinpixels, 0, dw );  

}  

程式測試代碼如下:

import java.awt.borderlayout;  

import java.awt.dimension;  

import java.awt.graphics;  

import java.awt.graphics2d;  

import java.io.file;  

import java.io.ioexception;  

import javax.imageio.imageio;  

import javax.swing.jcomponent;  

import javax.swing.jfilechooser;  

import javax.swing.jframe;  

public class bitbltfiltertest extends jcomponent {  

    private static final long serialversionuid = 7462704254856439832l;  

    private bufferedimage rawimg;  

    private bufferedimage modimg;  

    private dimension mysize;  

    public bitbltfiltertest(file f) {  

        try {  

            rawimg = imageio.read(f);  

            modimg = imageio.read(new file("d:\\resource\\geanmm.png"));  

            // modimg = imageio.read(new file("d:\\resource\\gloomyfish.png"));  

        } catch (ioexception e) {  

            e.printstacktrace();  

        mysize = new dimension(2*modimg.getwidth() + 20, modimg.getheight()+ 100);  

        filterimage();  

        final jframe imageframe = new jframe("emboss text - gloomyfish");  

        imageframe.getcontentpane().setlayout(new borderlayout());  

        imageframe.getcontentpane().add(this, borderlayout.center);  

        imageframe.setdefaultcloseoperation(jframe.exit_on_close);  

        imageframe.pack();  

        imageframe.setvisible(true);  

    private void filterimage() {  

        bitbltfilter filter = new bitbltfilter();  

        filter.emboss(rawimg, modimg);  

    public void paint(graphics g) {  

        graphics2d g2 = (graphics2d) g;  

        g2.drawimage(rawimg, 0, 0, rawimg.getwidth(), rawimg.getheight(), null);  

        g2.drawimage(modimg, rawimg.getwidth()+10, 0, modimg.getwidth(), modimg.getheight(), null);  

        g2.drawstring("text image", rawimg.getwidth()/2, rawimg.getheight()+10);  

        g2.drawstring("sharped text in image", modimg.getwidth() + 10, modimg.getheight()+10);  

    public dimension getpreferredsize() {  

        return mysize;  

    public dimension getminimumsize() {  

    public dimension getmaximumsize() {  

    public static void main(string[] args) {  

        jfilechooser chooser = new jfilechooser();  

        chooser.showopendialog(null);  

        file f = chooser.getselectedfile();  

        new bitbltfiltertest(f);  

繼續閱讀