• 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:"<<widthTime<<","<<"heightTime:"<<heightTime<<std::endl;
        uchar* data2 = (uchar*)(img2->imageData); //声明指针指向第二幅图像的数据区
    
        //保存各个区域的颜色值总量,以求平均值,先归零
        for(int row=0; row<img->height; row++)
            for(int cols=0; cols<img->width; 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:"<<row/heightTime<<",cols:"<<cols/widthTime<<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; row<img->height; row++) //操作数据区,要注意OpenCV的RGB的存储顺序为GBR
            for(int cols=0; cols<img->width; 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:"<<img2data[0][row][cols]<<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<height; row++)
            for(int cols=0; cols<width; 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:"<<row/heightTime<<",cols:"<<cols/widthTime<<std::endl;
                data2[row*img2->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<height; row++) //操作数据区,要注意OpenCV的RGB的存储顺序为GBR
            for(int cols=0; cols<width; cols++)
            {
                average += data[row*img->widthStep/sizeof(uchar)+cols*img->nChannels + 0];
            }
        average /= (height*width); //得到均值
        std::cout<<"average:"<<average<<std::endl;
    
        //二值化
        for(int row=0; row<height; row++)
            for(int cols=0; cols<width; 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<<"保存值之前:"<<std::bitset<32>(value1)<<std::bitset<32>(value2)<<std::endl;
    
        //计算图像的哈希值
        for(int row=0; row<height/2; row++) //前半部分
            for(int cols=0; cols<width; 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<height; row++) //后半部分
            for(int cols=0; cols<width; 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<<"保存值之后:"<<std::bitset<32>(value1)<<std::bitset<32>(value2)<<std::endl;//以二进制的形式输出
            std::cout<<"十六进制结果值:"<<std::hex<<value1<<value2<<std::endl; //以十六进制的形式输出:比如abcdef
            //将十六进制数保存到char类型里
            char char1[17];
            hextochar(value1, value2, char1); //十六进制数转char
            std::string str1 = char1; //将char数组char1保存到string变量str1中,用于文件名
            std::cout<<"字符串数组:"<<str1<<std::endl; //输出哈希值
    }

    结果:

        原图:

        压缩:

    灰值化:

    均值化:

    哈希值:

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

  • 相关阅读:
    Java 注解(Annotation)
    定时任务相关介绍
    Linux基础命令yum
    Linux基础命令rpm
    Linux基础命令date(如何设置时间? 如何同步时间?)
    Linux基础命令tar(如何压缩文件?如何解压文件?如何不解压查看内容?)
    Linux基础命令gzip
    Linux基础命令zip unzip (压缩 解压)
    Linux中压缩的概念(什么是压缩包?)
    Linux基础命令练习答案7.27
  • 原文地址:https://www.cnblogs.com/2008nmj/p/7390519.html
Copyright © 2020-2023  润新知