欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

校验两张BMP图像的RGB矩阵有多少个像素点不同

程序员文章站 2022-07-13 14:10:30
...

       数据结构课设我选的的二值图像(要求是.bmp格式)数字水印,代码实现之后,我就萌生了校验一下水印信息是否编码成功的想法。经水印算法编码后的二值图像,有的被编码图与原图不存在显著的人眼上的差异。这份代码我主要是用来检测:

       1、水印算法的稳健性;

       2、水印算法的安全性;

       3、水印算法的不可访问性;

       4、水印算法的有效性。

       具体用途将在课设答辩完成后,将课设代码、报告与详细说明一同写到博客里。

       另外,代码里面的析构函数如果加了那几行delete语句将引起程序运行时崩溃(RTE):或为两次释放内存。个人感觉问题出在 void OperateBMP::compareBMP() 函数里的两个OperateBMP类的调用,具体原因未分析。如有朋友有何高见,欢迎指教!

       

校验两张BMP图像的RGB矩阵有多少个像素点不同
图1 程序崩溃

 

校验两张BMP图像的RGB矩阵有多少个像素点不同
图2 正确运行时控制台结果

       

校验两张BMP图像的RGB矩阵有多少个像素点不同
图3 RGB矩阵比较结果(局部)

       

校验两张BMP图像的RGB矩阵有多少个像素点不同
图4 RGB矩阵比较结果(局部)

       

校验两张BMP图像的RGB矩阵有多少个像素点不同
图5 水印结果展示

       

       从图5明显看出编码前后图像的纹理有显著差异。

       开发环境:Ubuntu 16.04 LTS,g++。

       源代码:

#include <stdio.h>  
#include <string.h>  
#include <sys/types.h>  
#include <fstream>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <string>
 
#include <iostream>  
#pragma pack(2)
using namespace std;  
 
typedef struct BITMAPFILEHEADER  
{   
    u_int16_t bfType;   
    u_int32_t bfSize;   
    u_int16_t bfReserved1;   
    u_int16_t bfReserved2;   
    u_int32_t bfOffBits;   
}BITMAPFILEHEADER;   
typedef struct BITMAPINFOHEADER  
{   
    u_int32_t biSize;   
    u_int32_t biWidth;   
    u_int32_t biHeight;   
    u_int16_t biPlanes;   
    u_int16_t biBitCount;   
    u_int32_t biCompression;   
    u_int32_t biSizeImage;   
    u_int32_t biXPelsPerMeter;   
    u_int32_t biYPelsPerMeter;   
    u_int32_t biClrUsed;   
    u_int32_t biClrImportant;   
}BITMAPINFODEADER;  
 

class OperateBMP
{
public:
    int readBmp();
    int saveBmp();
    void work();
    void compareBMP();
    ~OperateBMP();

private:
    BITMAPFILEHEADER BMFH;
    BITMAPINFODEADER BMIH;
    int biWidth;            //图像宽  
    int biHeight;           //图像高  
    int biBitCount;         //图像类型,每像素位数  
    unsigned char *pBmpBuf; //存储图像数据  
    int lineByte;           //图像数据每行字节数

    string originFileName_string;
    string newFileName_string;
    const char *originFileName_char;
    const char *newFileName_char;

    string pictureName_without_type;

    //string resultName_string;
    char *resultName_char;
    int lengthOfResultName_char;

    string compareResult;
};


OperateBMP::~OperateBMP()
{
    /*
    delete pBmpBuf;
    delete originFileName_char;
    delete newFileName_char;
    delete resultName_char;
    */
}

int OperateBMP::readBmp()  
{  
    FILE *fp;  
    cout << "Please input the name of the origin BMP file:" << endl;
    cin >> originFileName_string;
    originFileName_char = new char[ originFileName_string.length() ];
    originFileName_char = originFileName_string.c_str();

    if( (fp = fopen(originFileName_char,"rb")) == NULL)  //以二进制的方式打开文件  
    {  
        cout<<"The file "<<originFileName_char<<"was not opened"<<endl;  
        return -1;  
    }  
    if(fseek(fp,sizeof(BITMAPFILEHEADER),SEEK_CUR))  //跳过BITMAPFILEHEADE  
    {  
        cout<<"跳转失败"<<endl;  
        return -1;  
    }  
    
    fread(&BMIH,sizeof(BITMAPINFOHEADER),1,fp);   //从fp中读取BITMAPINFOHEADER信息到infoHead中,同时fp的指针移动  
    biWidth = BMIH.biWidth;  
    biHeight = BMIH.biHeight;  
    biBitCount = BMIH.biBitCount;  
    lineByte = (biWidth*biBitCount/8+3)/4*4;   //lineByte必须为4的倍数
    //24位bmp没有颜色表,所以就直接到了实际的位图数据的起始位置  
    pBmpBuf = new unsigned char[lineByte * biHeight];  
    fread(pBmpBuf,sizeof(char),lineByte * biHeight,fp);  
    fclose(fp);   //关闭文件  
    return 0;  
}

int OperateBMP::saveBmp()  
{  
    FILE *fp;  
    newFileName_char = new char[ originFileName_string.length() + 4 ];
    newFileName_string = "New_" + originFileName_string;
    newFileName_char = newFileName_string.c_str();

    int pos = originFileName_string.find(".bmp");
    pictureName_without_type = originFileName_string.erase( pos, 4 );
    //cout << pictureName_without_type << endl;

    if( (fp = fopen(newFileName_char,"wb") )== NULL)   //以二进制写入方式打开  
    {  
        cout<<"打开失败!"<<endl;  
        return -1;  
    }  
    //设置BITMAPFILEHEADER参数  
    BMFH.bfType = 0x4D42;     
    BMFH.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + lineByte * biHeight;  
    BMFH.bfReserved1 = 0;  
    BMFH.bfReserved2 = 0;  
    BMFH.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);  
    fwrite(&BMFH,sizeof(BITMAPFILEHEADER),1,fp);  
    //设置BITMAPINFOHEADER参数  
    
    BMIH.biSize = 40;  
    BMIH.biWidth = biWidth;  
    BMIH.biHeight = biHeight;  
    BMIH.biPlanes = 1;  
    BMIH.biBitCount = biBitCount;  
    BMIH.biCompression = 0;  
    BMIH.biSizeImage = lineByte * biHeight;  
    BMIH.biXPelsPerMeter = 0;  
    BMIH.biYPelsPerMeter = 0;  
    BMIH.biClrUsed = 0;  
    BMIH.biClrImportant = 0;  
    //写入  
    fwrite(&BMIH,sizeof(BITMAPINFOHEADER),1,fp); 
 
 
    fwrite(pBmpBuf,sizeof(char),lineByte * biHeight,fp);  
    fclose(fp);    //关闭文件  
    return 0;  
}
void OperateBMP::work()  
{  
    if(-1 == readBmp())  
        cout<<"readfile error!"<<endl;  
    //输出图像的信息  
    cout<<"Width = "<<biWidth<<" Height = "<<biHeight<<" biBitCount="<<biBitCount<<endl;
    string TXT = "imageData_" + originFileName_string + ".txt"; //15

    const char *TXT_char = TXT.c_str();  

    resultName_char = new char[ 15 + originFileName_string.length() ];

    strcpy( resultName_char, TXT_char );

    lengthOfResultName_char = 15 + originFileName_string.length();
    ofstream outfile(TXT_char,ios::in | ios::trunc);  
    if(!outfile)  
    {  
        cout<<"open error"<<endl;  
        return ;  
    }  
    int count = 0;  
    //图像数据信息是从左下角按行开始存储的  
    for(int i = 0; i < biHeight; i++ )  
    {  
        for(int j = 0; j < biWidth; j++ )  
        {  
            for(int k = 0; k < 3; k++ )  
            {  
                int temp = *(pBmpBuf + i * lineByte + j + k);  
                count++;  
                outfile<<temp<<" ";  
                if(count % 8 == 0)  
                {  
                    outfile<<endl;  
                }  
            }  
        }  
    }  
    cout<<"总的像素数:"<<count / 3<<endl;
    newFileName_string = "_" + originFileName_string;
    newFileName_char = new char[ newFileName_string.length() ];
    newFileName_char = newFileName_string.c_str();  
    saveBmp();  
    
    return ;
}  
 
 void OperateBMP::compareBMP()
 {
    OperateBMP OBMP1, OBMP2;
    OBMP1.work();
    OBMP2.work();
    char *fileName1, *fileName2;
    fileName1 = new char[OBMP1.lengthOfResultName_char];
    strcpy(fileName1, OBMP1.resultName_char );
    fileName2 = new char[OBMP2.lengthOfResultName_char];
    strcpy( fileName2, OBMP2.resultName_char );


    FILE *fp1 = fopen( fileName1, "r" ), *fp2 = fopen( fileName2, "r" );

    int arr1[10], arr2[10], firstRow, firstColumn;
    int length = 0;
    long long cnt = 0;
    compareResult = OBMP1.pictureName_without_type + "_With_" + OBMP2.pictureName_without_type + "_Comparing_Result.txt";
    char *resultTXT = new char[ compareResult.length() ];//compareResultLength.c_str();
    strcpy( resultTXT, compareResult.c_str() );
    freopen( resultTXT, "w", stdout );
    while( ( fscanf( fp1, "%d %d %d %d %d %d %d %d \n", &arr1[0], &arr1[1], &arr1[2], &arr1[3], &arr1[4], &arr1[5], &arr1[6], &arr1[7] ) != EOF ) && ( fscanf( fp2, "%d %d %d %d %d %d %d %d \n", &arr2[0], &arr2[1], &arr2[2], &arr2[3], &arr2[4], &arr2[5], &arr2[6], &arr2[7] ) != EOF ) )
    {
        length ++;
        for( int i = 0; i < 7; i ++ )
        {
            if( arr1[i] != arr2[i] )
            {
                cnt ++;
                cout << "NO " << cnt << " difference:" << endl;
                cout << "row = " << length << ", " << "column = " << i + 1 << endl;
                printf( "In file %s\narr1[%d][%d] = %d\nIn file %s\narr2[%d][%d] = %d\n\n", fileName1,length, i + 1, arr1[i], fileName2, length, i + 1, arr2[i] );
                //break;
                //return 0;
            }
        }
    }
    delete fileName1;
    delete fileName2;
    if( cnt == 0 )
    {
        cout << "These two pictures come to one!" << endl;
    }

    delete fp1;
    delete fp2;
    delete resultTXT;
 }


int main(int argc,char *argv[])  
{ 
    
    OperateBMP OBMP;
    OBMP.compareBMP();
     
    return 0;  
}