OpenCV实现均值哈希

总共分三步:压缩,灰度化,均值化,求哈希值。

1.压缩

void secondMethod(char* filename, char* savename)
{
    //const char* filename2 = filename.c_str();
    //const char* savename2 = savename.c_str();
    //第一幅图像的参数
    IplImage* img = NULL; //OpenCV图像数据结构指针
    int width, height; //图像的宽和高
    //char* filename = "E:\\Pictures\\Me\\portrait.png"; //要打开图像的路径
    img = cvLoadImage(filename, 1); //打开图像,这个过去其实也完成了图像的解码,图像的信息存在IplImage指针所指的数据结构中
    uchar* data = (uchar*)(img->imageData); //声明指针指向图像的数据区
    width = img->width; //图像的宽
    height = img->height; //图像的高

    IplImage* img2; //均值后的图像
    //char* savename = "E:\\Pictures\\Me\\portrait4.png"; //要存储图像的路径
    img2 = cvCreateImage(cvSize(8, 8), img->depth, img->nChannels); //新建8X8的图像
    
    //图像压缩,将任意图像压缩成8x8的图像,保存到img2中 中间变量
    int img2data[3][8][8];//8x8列的数组 //其实应该是[8][8][3]还是[3][8][8] //不能设为uchar类型
    int widthTime, heightTime; //平均每个像素需要合并的次数
    widthTime = width/8;
    heightTime = height/8;
    
    std::cout<<"widthTime:"<std::endl;
    uchar* data2 = (uchar*)(img2->imageData); //声明指针指向第二幅图像的数据区

    //保存各个区域的颜色值总量,以求平均值,先归零
    for(int row=0; rowheight; row++)
        for(int cols=0; colswidth; cols++)
        {
            if(row/heightTime<8 && cols/widthTime<8)
            {
                img2data[0][row/heightTime][cols/widthTime] = 0; //第一幅图颜色的和保存在数组,先归零
                img2data[1][row/heightTime][cols/widthTime] = 0;
                img2data[2][row/heightTime][cols/widthTime] = 0;

                data2[row/heightTime*img2->widthStep/sizeof(uchar)+cols/widthTime*img2->nChannels + 0] = 0; //第二幅图的颜色值归零,一定要是img2->widthStep img2->nChannels
                std::cout<<"row:"<std::endl;
                data2[row/heightTime*img2->widthStep/sizeof(uchar)+cols/widthTime*img2->nChannels + 1] = 0;
                data2[row/heightTime*img2->widthStep/sizeof(uchar)+cols/widthTime*img2->nChannels + 2] = 0;
            }
        }
    //求和,保存在数组
    for(int row=0; rowheight; row++) //操作数据区,要注意OpenCV的RGB的存储顺序为GBR
        for(int cols=0; colswidth; cols++)
        {
            if(row/heightTime<8 && cols/widthTime<8)
            {
                img2data[0][row/heightTime][cols/widthTime] += data[row*img->widthStep/sizeof(uchar)+cols*img->nChannels + 0];
                img2data[1][row/heightTime][cols/widthTime] += data[row*img->widthStep/sizeof(uchar)+cols*img->nChannels + 1];
                img2data[2][row/heightTime][cols/widthTime] += data[row*img->widthStep/sizeof(uchar)+cols*img->nChannels + 2];
            }

        }

    //求平均值后,保存到第二幅图的数据区
    for(int row=0; row<8; row++) //操作数据区,要注意OpenCV的RGB的存储顺序为GBR
    for(int cols=0; cols<8; cols++)
    {
        if(row/heightTime<8 && cols/widthTime<8)
        {
            data2[row*img2->widthStep/sizeof(uchar)+cols*img2->nChannels + 0] = img2data[0][row][cols]/heightTime/widthTime; //G /100.0 /heightTime/widthTime
            std::cout<<"0:"<std::endl;
            data2[row*img2->widthStep/sizeof(uchar)+cols*img2->nChannels + 1] = img2data[1][row][cols]/heightTime/widthTime; //B /100.0 /heightTime/widthTime
            data2[row*img2->widthStep/sizeof(uchar)+cols*img2->nChannels + 2] = img2data[2][row][cols]/heightTime/widthTime; //R /100.0 /heightTime/widthTime

        }
    }
    cvSaveImage(savename, img2); //存储图像
    cvNamedWindow("show", 1); //创建窗口对象用于显示
    cvShowImage("show", img2); //将图像显示在窗口上
    cvWaitKey(0);
    cvReleaseImage(&img); //释放图像数据结构指针对象所指内容
    cvReleaseImage(&img2);
}

2. 灰值化

void gray(char* savename, char* graysavename)//第一个参数为压缩后的保存地址,第二个参数为灰度后的保存地址
{
    //第一幅图像的参数
    IplImage* img = NULL; //OpenCV图像数据结构指针
    int width, height; //图像的宽和高
    img = cvLoadImage(savename, 1); //打开图像,这个过去其实也完成了图像的解码,图像的信息存在IplImage指针所指的数据结构中
    uchar* data = (uchar*)(img->imageData); //声明指针指向图像的数据区
    width = img->width; //图像的宽
    height = img->height; //图像的高

    IplImage* img2; //灰度化的图像
    //char* savename = "E:\\Pictures\\Me\\portrait4.png"; //要存储图像的路径
    img2 = cvCreateImage(cvSize(8, 8), img->depth, 1); //新建灰度的图像
    
    //中间变量
    int img2data[1][8][8];//8x8列的数组 //其实应该是[8][8][3]还是[3][8][8] //不能设为uchar类型
    int img2dataB[1][8][8], img2dataG[1][8][8], img2dataR[1][8][8];
    uchar* data2 = (uchar*)(img2->imageData); //声明指针指向第二幅图像的数据区

    //灰度化:公式:I = 0.3B + 0.59G + 0.11R
    //先将值保存到img2dataB[1][8][8], img2dataG[1][8][8], img2dataR[1][8][8]
    for(int row=0; row)
        for(int cols=0; cols)
        {
            //G
            img2dataG[0][row][cols] = data[row*img->widthStep/sizeof(uchar)+cols*img->nChannels + 0]; //第一幅图颜色的和保存在数组,先归零
            //B
            img2dataB[0][row][cols] = data[row*img->widthStep/sizeof(uchar)+cols*img->nChannels + 1];
            //R
            img2dataR[0][row][cols] = data[row*img->widthStep/sizeof(uchar)+cols*img->nChannels + 2];

            img2data[0][row][cols] = 0.1140*img2dataB[0][row][cols] + 0.5870*img2dataG[0][row][cols] + 0.2989*img2dataR[0][row][cols];


            data2[row*img2->widthStep/sizeof(uchar)+cols*img2->nChannels + 0] = img2data[0][row][cols]; //第二幅图的颜色值归零,一定要是img2->widthStep img2->nChannels
            /*std::cout<<"row:"<widthStep/sizeof(uchar)+cols*img2->nChannels + 1] = 0;
            data2[row*img2->widthStep/sizeof(uchar)+cols*img2->nChannels + 2] = 0;*/
        }

    cvSaveImage(graysavename, img2); //存储图像
    cvNamedWindow("show", 1); //创建窗口对象用于显示
    cvShowImage("show", img2); //将图像显示在窗口上
    cvWaitKey(0);
    cvReleaseImage(&img); //释放图像数据结构指针对象所指内容
    cvReleaseImage(&img2);
}

3. 均值化

void average(char* graysavename)
{
    //第一幅图像的参数
    IplImage* img = NULL; //OpenCV图像数据结构指针
    int width, height; //图像的宽和高
    img = cvLoadImage(graysavename, 1); //打开图像,这个过去其实也完成了图像的解码,图像的信息存在IplImage指针所指的数据结构中
    uchar* data = (uchar*)(img->imageData); //声明指针指向图像的数据区
    width = img->width; //图像的宽
    height = img->height; //图像的高

    //第二幅图像的参数:二值化
    IplImage* img2 = NULL;
    img2 = cvCreateImage(cvSize(8, 8), img->depth, 1);
    uchar* data2 = (uchar*)(img2->imageData);

    //计算均值
    double average = 0.0;
    for(int row=0; row//操作数据区,要注意OpenCV的RGB的存储顺序为GBR
        for(int cols=0; cols)
        {
            average += data[row*img->widthStep/sizeof(uchar)+cols*img->nChannels + 0];
        }
    average /= (height*width); //得到均值
    std::cout<<"average:"<std::endl;

    //二值化
    for(int row=0; row)
        for(int cols=0; cols)
        {
            //对比该像素点的灰度值与平均值
            uchar pixeldata = data[row*img->widthStep/sizeof(uchar)+cols*img->nChannels + 0];
            if(pixeldata>=average)
            {
                data2[row*img2->widthStep/sizeof(uchar)+cols*img2->nChannels + 0] = 255;
            }
            else
            {
                data2[row*img2->widthStep/sizeof(uchar)+cols*img2->nChannels + 0] = 0;
            }
        }

    cvSaveImage("E:\\Pictures\\Me\\portrait6.png", img2); //存储图像
    cvNamedWindow("show", 1); //创建窗口对象用于显示
    cvShowImage("show", img2); //将图像显示在窗口上
    cvWaitKey(0);
    cvReleaseImage(&img); //释放图像数据结构指针对象所指内容
    cvReleaseImage(&img2);
}

4. 求哈希值

void getHash(char* twovaluefilename)
{
    //第一幅图像的参数
    IplImage* img = NULL; //OpenCV图像数据结构指针
    int width, height; //图像的宽和高
    img = cvLoadImage(twovaluefilename, 1); //打开图像,这个过去其实也完成了图像的解码,图像的信息存在IplImage指针所指的数据结构中
    uchar* data = (uchar*)(img->imageData); //声明指针指向图像的数据区
    width = img->width; //图像的宽
    height = img->height; //图像的高

    long int value1 = 0x00000000; //保存位的值,由于C++不允许以二进制保存,所以用的0x十六进制保存的,总共4*8=32位
    long int value2 = 0x00000000; //value1为前32位,value2为后32位
    std::cout<<"保存值之前:"<32>(value1)<32>(value2)<<std::endl;

    //计算图像的哈希值
    for(int row=0; row2; row++) //前半部分
        for(int cols=0; cols)
        {
            //对比该像素点的灰度值与平均值
            uchar pixeldata = data[row*img->widthStep/sizeof(uchar)+cols*img->nChannels + 0];
            if(pixeldata>=1) //白色 
            {
                value1 |= (1<<(32 - (row*8+cols) -1));
            }
            else
            {
                //
            }
        }
    for(int row=height/2; row//后半部分
        for(int cols=0; cols)
        {
            //对比该像素点的灰度值与平均值
            uchar pixeldata = data[row*img->widthStep/sizeof(uchar)+cols*img->nChannels + 0];
            if(pixeldata>=1) //白色 
            {
                value2 |= (1<<(32 - (row*8+cols) -1));
            }
            else
            {
                //
            }
        }
        std::cout<<"保存值之后:"<32>(value1)<32>(value2)<//以二进制的形式输出
        std::cout<<"十六进制结果值:"<//以十六进制的形式输出:比如abcdef
        //将十六进制数保存到char类型里
        char char1[17];
        hextochar(value1, value2, char1); //十六进制数转char
        std::string str1 = char1; //将char数组char1保存到string变量str1中,用于文件名
        std::cout<<"字符串数组:"<//输出哈希值
}

 

结果:

    原图:

    压缩:

灰值化:

均值化:

哈希值:

 这时候,比较两个图片的相似性,就是先计算这两张图片的hash指纹,也就是64位0或1值,然后计算不同位的个数(汉明距离)。如果这个值为0,则表示这两张图片非常相似,如果汉明距离小于5,则表示有些不同,但比较相近,如果汉明距离大于10则表明完全不同的图片。(该段转自:原文。)

转载于:https://www.cnblogs.com/2008nmj/p/7390519.html

你可能感兴趣的:(OpenCV实现均值哈希)