去除简单水印方法的讨论(原创)

本文介绍了一种去除简单水印的方法,适用于通过图像叠加方式添加的水印。通过公式推导,提出利用图像的Alpha通道信息进行处理,以恢复原图像。文章以TGA文件为例,详细讲解了读取、处理和保存图像的步骤,并提醒该方法不适用于完全叠加或特定透明度情况,同时强调合法使用的必要性。

因为前段时间跟CG方面打了不少交道,所以产生了今天的问题.

 

 

 

 

 

对于视频的合成,我们可能都需要用到很多地方的素材,来源于各个地方,包括电视台,大部分素材都有一个共同点,都加了水印或台标.可以想像,在制作我们自己的作品时,肯定不能出现别人的标志,所以我们得去除原来的水印(注:在不侵犯别人的权利的前提下).今天我们只讨论对简单水印的处理.

 

 

 

 

 

先看一张加了水印的图:

<img src=http://www.bezier.com.cn/study/1.jpg>

 

 

 

 

 

 

 

 

 

 

其实我们可以看出,这个最终的图(C)其实是用另一张标志图(B)与原图(A)叠加而得到(叠加的方式这里就不作讨论,有兴趣的可以去参看参考书),叠加时赋予了一定的透明度(Tran).

 

 

 

 

 

这时,我们可以大概的形成一个公式:

 

 

 

 

 

A+ B*Tran=C

 

 

 

 

 

但是按此公式的话,原图像没有任何修改,标志图的象素值全部叠加原图像上,最张图像应该变亮,而事实上却没有,那肯定原图像在叠加过程中也有了一定的衰减过程(Atten)

 

 

 

 

 

:

 

 

 

 

 

A*Atten + B*Tran=C

 

 

 

 

 

 

 

 

 

 

 

推测标志图增加了多少值,原图像应该减少多少,即Atten=1-Tran.

 

 

 

 

 

经测试确实是如此(测试过程省略)

 

 

 

 

 

A*(1-Tran) + B*Tran=C

 

 

 

 

 

由此,我们如果想把加过水印的图像恢复到原样,只需要:

 

 

 

 

 

A=(C-B*Tran)/(1-Tran).

 

 

 

 

 

公式已经出来了,下面我们就开时做了。

 

 

 

 

 

 

 

 

 

 

 

这时候我们引入一个常用且普通的图像文件类型:TGA

 

 

 

 

 

这种文件格式简单,它由头文件、数据文件、附加文件构成。

 

 

 

 

 

 

 

 

 

 

 

TGA头文件结构

 

 

 

 

 

struct TargaHeader

 

 

 

 

 

{

 

 

 

 

 

BYTE IDLength;

 

 

 

 

 

BYTE ColormapType;

 

 

 

 

 

BYTE ImageType;//如果为02则表示未压缩,(A0)表示压缩

 

 

 

 

 

BYTE ColormapSpecification[5];

 

 

 

 

 

WORD XOrigin;

 

 

 

 

 

WORD YOrigin;

 

 

 

 

 

WORD ImageWidth;//图像宽度

 

 

 

 

 

WORD ImageHeight;//图像高度

 

 

 

 

 

BYTE PixelDepth;//图像色彩位数

 

 

 

 

 

BYTE ImageDescriptor;//应该是表示图像反正的,08表示反,其他表示正(或者反着来)

 

 

 

 

 

} tga;

 

 

 

 

 

//总共18个字节

 

 

 

 

 

 

 

 

 

 

 

我们进行处理时,只要先跳过前18个字节,直接对其数据部分进行处理。数据部分是按BGRA来排列,即蓝色、绿色、红色、Alpha通道值来分布。所以我们要处理的数据部分的大小为ImageWidth* ImageHeight*4。之所以用这种文件格式,因为其格式简单,同时,这种文件包含了图像的Alpha通道信息,有了这层Alpha值信息,我们可很容易的把图像中所需要的部分提取出来,这里就不多讲了,有兴趣的朋友可以跟我联系。

 

 

 

 

 

 

 

 

 

 

 

现在我们来读原图像文件(代码中,padfile,tran都是另外定义):

 

 

 

 

 

int RemoveMask(char *filename)

 

 

 

 

 

{

 

 

 

 

 

 

 

 

 

 

 

//这里读入加了水印的图像

 

 

 

 

 

FILE *fp=fopen(filename, "rb");

 

 

 

 

 

    fseek(fp, 0, SEEK_END);

 

 

 

 

 

    int len=ftell(fp);

 

 

 

 

 

    unsigned char *tgadata;

 

 

 

 

 

    tgadata=new unsigned char[len+1];

 

 

 

 

 

    tgadata[len]=0;

 

 

 

 

 

    fseek(fp, 0, SEEK_SET);

 

 

 

 

 

    fread(tgadata, len, 1, fp);

 

 

 

 

 

    fclose(fp);        

 

 

 

 

 

    if(!((tgadata[16]==24 || tgadata[16]==32) && (tgadata[2]==2 || tgadata[2]==10)))//判断图像色彩位数和压缩属性是否正确

 

 

 

 

 

        return 0;

 

 

 

 

 

    int sx=*((unsigned short *)&tgadata[12]);//获得图像x大小

 

 

 

 

 

    int sy=*((unsigned short *)&tgadata[14]);// 获得图像y大小

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

///这里读入单纯的水印图像文件。这里不免有人问,这个文件哪来呢?本例子中因为是我自己做的,所以有原始的标志文件,但用别人的加了水印的文件时,哪来的这个文件呢?我这里只可以说的是,可以用Photoshop做一个,当然怎么做这些问题我就不提了。

 

 

 

 

 

FILE *fp2=fopen(psdfile, "rb");

 

 

 

 

 

    fseek(fp2, 0, SEEK_END);

 

 

 

 

 

    int len2=ftell(fp2);

 

 

 

 

 

    unsigned char *psddata;

 

 

 

 

 

    psddata=new unsigned char[len2+1];

 

 

 

 

 

    psddata[len2]=0;

 

 

 

 

 

    fseek(fp2, 0, SEEK_SET);

 

 

 

 

 

    fread(psddata, len2, 1, fp2);

 

 

 

 

 

    fclose(fp2);   

 

 

 

 

 

    if(!((psddata[16]==24 || psddata[16]==32) && (psddata[2]==2 || psddata[2]==10)))

 

 

 

 

 

        return 0;

 

 

 

 

 

 

 

 

 

 

 

    //////////////去除标志运算//////////////////////////////

 

 

 

 

 

    int pixel=1;

 

 

 

 

 

    int allpixel=sx*sy;

 

 

 

 

 

 

 

 

 

 

 

    for(int j=18;j<allpixel*4+18;j+=4)//跳过头文件进行检测,每四个象素值为一个单元

 

 

 

 

 

    {

 

 

 

 

 

       

 

 

 

 

 

        if(psddata[j+3]!=0)//此值为通道值,如果通道值为0,表示该单元的色彩信息是不显示的,这里就涉及到了刚才所说的Alpha值的应用

 

 

 

 

 

        {

 

 

 

 

 

                    pixel=(int)((tgadata[j]-psddata[j]*tran*psddata[j+3]/255)/(1-tran*psddata[j+3]/255));//这里就为刚才的公式的应用,对原象素的值进行还原,依次对BGA各值进行还原,此处为蓝色值

 

 

 

 

 

 

 

 

 

 

 

            if(pixel>255)

 

 

 

 

 

                tgadata[j]=255;

 

 

 

 

 

            else if (pixel<0) tgadata[j]=0;

 

 

 

 

 

            else

 

 

 

 

 

                tgadata[j]=(unsigned char)pixel;

 

 

 

 

 

            /////////GGGG////////

 

 

 

 

 

            pixel=(int)((tgadata[j+1]-psddata[j+1]*tran*psddata[j+3]/255)/(1-tran*psddata[j+3]/255));// 此处为绿色值

 

 

 

 

 

            if(pixel>255)

 

 

 

 

 

                tgadata[j+1]=255;

 

 

 

 

 

            else if (pixel<0) tgadata[j+1]=0;

 

 

 

 

 

            else

 

 

 

 

 

                tgadata[j+1]=(unsigned char)pixel;

 

 

 

 

 

       

 

 

 

 

 

            pixel=(int)((tgadata[j+2]-psddata[j+2]*tran*psddata[j+3]/255)/(1-tran*psddata[j+3]/255)); //此处为红色值

 

 

 

 

 

            if(pixel>255)

 

 

 

 

 

                tgadata[j+2]=255;

 

 

 

 

 

            else if (pixel<0) tgadata[j+2]=0;

 

 

 

 

 

            else

 

 

 

 

 

                tgadata[j+2]=(unsigned char)pixel;

 

 

 

 

 

        }

 

 

 

 

 

    }

 

 

 

 

 

    //////////////////保存为文件////////////////////////////////

 

 

 

 

 

    if ((fp=fopen(filename,"wb"))!=0)

 

 

 

 

 

    {

 

 

 

 

 

        fwrite(tgadata,1,len,fp);//每个值已经进行了还原,写入覆盖原文件

 

 

 

 

 

    }

 

 

 

 

 

 

 

 

 

 

 

    fclose(fp);

 

 

 

 

 

    delete []tgadata;

 

 

 

 

 

    delete []psddata;

 

 

 

 

 

 

 

 

 

 

 

    return 1;

 

 

 

 

 

 

 

 

 

 

 

}

 

 

 

 

 

<img src=http://www.bezier.com.cn/study/2.jpg>

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

值得说明的是,此法只针对用图像进行叠加所产生的水印,如用Photoshop或后期软件进行轨道的合成,比如Adobe Premiere, Sony Vegas等。在对视频文件时,我们可以用这些软件把其导出成TGA序列,然后对每帧序列文件进行处理,最后再合成,就形成了原始的视频文件了。

同时,由公式可以看出,当水印是不用透明度,完全叠加时,就失去原图的信息,此法就不合适了.同时,水印透明度的指定也是先依照估计,然后逐渐取最近值的做法

 

 

 

 

 

警告:此法只供学习交流使用,禁止用于非法途径,尊重知识产权!

 

 

 

 

 

 

 

 

 

 

 

有兴趣的朋友可以跟我继续交流。大家也可以尝试采用BMP,JPG文件结构。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值