zoukankan      html  css  js  c++  java
  • 数字图像处理第一次作业

    话说数字图像作业可是真多啊.而网上找的版本大都是Matlab做的,为了使学弟学妹们的可用的版本多一点,想着数字图像处理怎么可以没有OpenCV这个大杀器,尽管用OpenCV确实是比Matlab要麻烦很多,但是为了提高自己的编程能力, 本着我不入地狱谁入地狱的原则, 也是为了给我可爱的学弟学妹们留下一点财富吧.(你的老师要是也布置这样的作业, 那毫无疑问, 咱们是一个大学的, 甚至我们的老师都是同一个人, 当你们默默的复制粘贴时, 可千万不要忘了你们的学长啊).

    进入正题,本次主要解决五个问题

    1、Bmp图像格式简介;
    2、把lena 512*512图像灰度级逐级递减8-1显示;
    3、计算lena图像的均值方差;
    4、把lena图像用近邻、双线性和双三次插值法zoom到2048*2048;
    5、把lena和elain图像分别进行水平shear(参数可设置为1.5,或者自行选择)和旋转30度,并采用用近邻、双线性和双三次插值法zoom到2048*2048;

    一、  BMP图像格式简介

    BMP( Bitmap-File )图形文件是Windows采用的图形文件格式,在Windows环境下运行的所有图像处理软件都支持BMP图像文件格式。 Windows系统内部各图像绘制操作都是以BMP为基础的。Windows 3.0以前的BMP图像文件格式与显示设备有关,因此把这种BMP图像文件格式称为设备相关位图DDB( device-dependent bitmap )文件格式。Windows 3.0以后的BMP图像文件与显示设备无关,因此把这种BMP图像文件格式称为设备无关位图DIB( device-independent bitmap )格式。

    Windows 3.0以后,在系统中仍然存在DDB位图。像 BitBlt 这种函数就是基于DDB位图的,只不过如果你想将图像以BMP格式保存到磁盘文件中时,微软极力推荐你以DIB格式保存,目的是为了让Windows能够在任何类型的显示设备上显示所存储的图像。BMP位图文件默认的文件扩展名是BMP或者bmp,有时它也会以.DIB或.RLE作扩展名。

    二、  把lena 512*512图像灰度级逐级递减8-1显示

    原图像

                                     Lena                                                                                        elain 

    本次应当对单个像素点一一处理,故使用了cvGet2D来取每一个像素点的值,通过整形和浮点型的运算来分级,然后通过cvSet2D函数设置每个像素点的值。具体程序请向后翻,其实博主事先是想用指针对数组操作来处理的,但是总是报内存错误,不清楚是哪儿的原因,好像是OpenCV内部函数的缘故,当做加减法时,会出现条纹,当做乘除法时,直接报错,调试时发现单个像素点可以达到1.6*e10的值,远大于256,不明所以。还请高手明示。这是用指针时的代码

    //对行 进行遍历
            for(y=0;y<mat_3Chanel.rows;y++)
            {
                    //将指针偏移到第y行 的起始处
                    float* p_float = (float*)(mat_3Chanel.data.ptr + y*mat_3Chanel.step) ;
    
                    //对第y行的 元素进行遍历
                    for(x=0;x<mat_3Chanel.cols;x++)
                    {
                             *(p_float+x*nChannels) = int(*(p_float+x*nChannels)/2.0)*2; //指针偏移到第y行的第x个元素的起始处
    
                    }
            }        

    正确代码请往后翻啊,先贴个例子,这是将Lena化为两个灰度级的核心函数

    cv::Scalar pixel1;
    
        //int nChannels = 1;
        for(y=0;y<lena->height;y++)
        {
            for(x=0;x<lena->width;x++)
            {
                //得到一个像素的值
                pixel1 = cvGet2D( lena, y, x);
    
                //转换
                pixel1.val[0] = int(pixel1.val[0]/128.0)*128;
    
                //设置格式
                cvSet2D( lena1, y, x, pixel1 );
    
            }
        } 

    最后结果

    总结一下哈:

    当遇见暂时不能解决的问题时,要想想还有没有其他的办法,其他原来看不好的办法是不是在本题中可以很好使用,不要耗在一点上不动,白浪费时间。

    三、  计算lena图像的均值方差;

    分析

    计算均值方差考虑到函数cvAvgSdv, 由函数直接得出答案.

    直接上代码

        CvScalar Avg;
        CvScalar std_dev;
    
        cvAvgSdv( lena, &Avg, &std_dev);
    
        cout<<"averege is "<<Avg.val[0]<<endl;
        cout<<"std_dev is "<<std_dev.val[0]<<endl;

    结果

    均值为99.0512      标准差为52.8775

    四、  把lena图像用近邻、双线性和双三次插值法zoom到2048*2048;

    调用函数cvResize, 其核心代码是

        cvResize(lena, lena_NN, CV_INTER_NN);
        cvResize(lena, lena_LINEAR, CV_INTER_LINEAR);
        cvResize(lena, lena_CUBIC, CV_INTER_CUBIC);

    其中CV_INTER_NN代表的是近邻插值法, CV_INTER_LINEAR代表的是双线性插值法, CV_INTER_CUBIC代表的是双三次插值法

    又由于2048*2048的图像过大,不易于显示,故采用CV_WINDOW_NORMAL形式显示.

    对了这个程序还有一个小bug,我给lena_NN创建窗口时,用了CV_WINDOW_NORMAL,但是显示时还是很大,不知道为什么

    结果

    总结一下

    三者仅凭肉眼是很难看出差别的,与原图像相比也很难找出不同之处,表示这三者在对图像的显示方面都是很好的。

    五、  把lena和elain图像分别进行水平shear(参数可设置为1.5,或者自行选择)和旋转30度,并采用用近邻、双线性和双三次插值法zoom到2048*2048;

    注:下面大段引用小魏的博客,其实我觉的她讲的比我好多了,建议你们想搞明白的直接去翻她的博客,网址:http://blog.csdn.net/xiaowei_cqu/article/details/7616044

    好,我们继续

    分析

    几何变换可以看成图像中物体(或像素)空间位置改变,或者说是像素的移动。

    几何运算需要空间变换和灰度级差值两个步骤的算法,像素通过变换映射到新的坐标位置,新的位置可能是在几个像素之间,即不一定为整数坐标。这时就需要灰度级差值将映射的新坐标匹配到输出像素之间。最简单的插值方法是最近邻插值,就是令输出像素的灰度值等于映射最近的位置像素,该方法可能会产生锯齿。插值算法感觉只要了解就可以了,图像处理中比较需要理解的还是空间变换。

    空间变换对应矩阵的仿射变换。一个坐标通过函数变换的新的坐标位置:

     

    所以在程序中我们可以使用一个2*3的数组结构来存储变换矩阵:

     

    以最简单的平移变换为例,平移(b1,b2)坐标可以表示为:

     

    因此,平移变换的变换矩阵及逆矩阵记为:

     

    缩放变换:将图像横坐标放大(或缩小)sx倍,纵坐标放大(或缩小)sy倍,变换矩阵及逆矩阵为:

     

    选择变换:图像绕原点逆时针旋转a角,其变换矩阵及逆矩阵(顺时针选择)为:

     

    OpenCV中的图像变换函数

    基本的放射变换函数:

    void cvWarpAffine(   
        const CvArr* src,//输入图像  
        CvArr* dst, //输出图像  
        const CvMat* map_matrix,   //2*3的变换矩阵  
        int flags=CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS,   //插值方法的组合  
        CvScalar fillval=cvScalarAll(0)   //用来填充边界外的值  
    );  

    另外一个比较类似的函数是cvGetQuadrangleSubPix:

    void cvGetQuadrangleSubPix(   
           const CvArr* src,  //输入图像   
           CvArr* dst,   // 提取的四边形  
           const CvMat* map_matrix //2*3的变换矩阵  
    );  

    这个函数用以提取输入图像中的四边形,并通过map_matrix变换存储到dst中,与WarpAffine变换意义相同,

    即对应每个点的变换:

    WarpAffine与 GetQuadrangleSubPix 不同的在于cvWarpAffine 要求输入和输出图像具有同样的数据类型,有更大的资源开销(因此对小图像不太合适)而且输出图像的部分可以保留不变。而 cvGetQuadrangleSubPix 可以精确地从8位图像中提取四边形到浮点数缓存区中,具有比较小的系统开销,而且总是全部改变输出图像的内容。

    首先对shear. 在OpenCV 2.3的参考手册中《opencv_tutorials》介绍了一种确定变换矩阵的方法,通过三个点变换的几何关系映射实现变换。

     

    shear核心代码

    srcTri[0] = Point2f( 0,0 ); 
    
        srcTri[1] = Point2f( src.cols - 1, 0 ); 
    
        srcTri[2] = Point2f( 0, src.rows - 1 ); 
    
        dstTri[0] = Point2f( src.cols*0.0, src.rows*0.0); 
    
        dstTri[1] = Point2f( src.cols * 0.5, src.rows*0.0 ); 
    
        dstTri[2] = Point2f( src.cols*0.5, src.rows - 1 );
    
     
    
        warp_mat = getAffineTransform( srcTri, dstTri ); 
    
    warpAffine( src, warp_dst, warp_mat, warp_dst.size() );

    然后就是扩展至2048*2048 , 其核心代码为

        cv::resize( warp_dst , lena_shear_NN,cv::Size(2048,2048),CV_INTER_NN);
    
        cv::resize( warp_dst , lena_shear_LINEAR,cv::Size(2048,2048),CV_INTER_LINEAR);
    
        cv::resize( warp_dst , lena_shear_CUBIC,cv::Size(2048,2048),CV_INTER_CUBIC);
    
     

    然后对旋转30度的

     

    构造旋转矩阵

        CvPoint2D32f center = cvPoint2D32f(width / 2, height / 2);   
    
        cv2DRotationMatrix(center, 30, 1.0, &map_matrix);   
    
        map[2] += (width_rotate - width) / 2;   
    
        map[5] += (height_rotate - height) / 2;

    然后就是旋转运算和放大(690是博主试了好多次才试出来的,大小刚好撑得下512旋转30度)

        cv::warpAffine( elain ,elain_rotate_NN, map_matrix1,cv::Size(690,690),CV_INTER_NN);
    
        cv::warpAffine( elain ,elain_rotate_LINEAR, map_matrix1,cv::Size(690,690),CV_INTER_LINEAR);
    
        cv::warpAffine( elain ,elain_rotate_CUBIC, map_matrix1,cv::Size(690,690),CV_INTER_CUBIC);
    
     
    
        cv::resize( elain_rotate_NN, elain_rotate_NN, cv::Size(2048,2048),CV_INTER_NN);
    
        cv::resize( elain_rotate_LINEAR, elain_rotate_LINEAR, cv::Size(2048,2048),CV_INTER_LINEAR);
    
        cv::resize( elain_rotate_CUBIC, elain_rotate_CUBIC, cv::Size(2048,2048),CV_INTER_CUBIC);

    结果

    六、  总结

    OpenCV确实是比Matlab要麻烦很多,但是可以加强我们的动手能力, 同时加强我们对图像本质的认识,不过,我认为从中学到的东西最重要的是面对困难时的心态和方法, 以及当面对位置问题时分析问题,解决问题的能力和信心吧,毕竟问题是永远也解决不完的,但是我们可以改变的是面对困难时的态度提升的是我们的能力, 还有一点是小魏说的,我觉的挺好的,就是别人总结出来的东西能帮助我们在一开始迅速入门,但要学深,学精,终归还是要自己去努力挖的。

    七、  源代码

    // Homework No1.cpp : Defines the entry point for the console application.
    // houqiqi 
    
    #include "stdafx.h"
    #include <iostream>
    #include "highgui.h"
    #include "cv.h"
    #include "cxcore.h"
    #include "math.h"
    
    using namespace std;
    using namespace cv;
    
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        //load the image lena
        IplImage* lena = cvLoadImage ( "C:\\Users\\qiqi\\Desktop\\第一次作业[1]\\lena.bmp",0);
    
    
        IplImage* lena1 = cvCreateImage( cvGetSize( lena ), lena->depth, lena->nChannels);
        IplImage* lena2 = cvCreateImage( cvGetSize( lena ), lena->depth, lena->nChannels);
        IplImage* lena3 = cvCreateImage( cvGetSize( lena ), lena->depth, lena->nChannels);
        IplImage* lena4 = cvCreateImage( cvGetSize( lena ), lena->depth, lena->nChannels);
        IplImage* lena5 = cvCreateImage( cvGetSize( lena ), lena->depth, lena->nChannels);
        IplImage* lena6 = cvCreateImage( cvGetSize( lena ), lena->depth, lena->nChannels);
        IplImage* lena7 = cvCreateImage( cvGetSize( lena ), lena->depth, lena->nChannels);
        IplImage* lena8 = cvCreateImage( cvGetSize( lena ), lena->depth, lena->nChannels);
    
    
        //create windows 
        cv::namedWindow( "lena8", CV_WINDOW_AUTOSIZE );
        cv::namedWindow( "lena7", CV_WINDOW_AUTOSIZE );
        cv::namedWindow( "lena6", CV_WINDOW_AUTOSIZE );
        cv::namedWindow( "lena5", CV_WINDOW_AUTOSIZE );
        cv::namedWindow( "lena4", CV_WINDOW_AUTOSIZE );
        cv::namedWindow( "lena3", CV_WINDOW_AUTOSIZE );
        cv::namedWindow( "lena2", CV_WINDOW_AUTOSIZE );
        cv::namedWindow( "lena1", CV_WINDOW_AUTOSIZE );
    
        int y, x; 
        float temp;
        
        cv::Scalar pixel1;
        cv::Scalar pixel2;
        cv::Scalar pixel3;
        cv::Scalar pixel4;
        cv::Scalar pixel5;
        cv::Scalar pixel6;
        cv::Scalar pixel7;
        cv::Scalar pixel8;
    
        //int nChannels = 1;
        for(y=0;y<lena->height;y++)
        {
            for(x=0;x<lena->width;x++)
            {
                //
                pixel1 = cvGet2D( lena, y, x);
                pixel2 = cvGet2D( lena, y, x);
                pixel3 = cvGet2D( lena, y, x);
                pixel4 = cvGet2D( lena, y, x);
                pixel5 = cvGet2D( lena, y, x);
                pixel6 = cvGet2D( lena, y, x);
                pixel7 = cvGet2D( lena, y, x);
                pixel8 = cvGet2D( lena, y, x);
    
                //
                pixel1.val[0] = int(pixel1.val[0]/128.0)*128;
                pixel2.val[0] = int(pixel2.val[0]/64.0)*64;
                pixel3.val[0] = int(pixel3.val[0]/32.0)*32;
                pixel4.val[0] = int(pixel4.val[0]/16.0)*16;
                pixel5.val[0] = int(pixel5.val[0]/8.0)*8;
                pixel6.val[0] = int(pixel6.val[0]/4.0)*4;
                pixel7.val[0] = int(pixel7.val[0]/2.0)*2;
                pixel8.val[0] = int(pixel8.val[0]/1.0)*1;
    
                //
                cvSet2D( lena1, y, x, pixel1 );
                cvSet2D( lena2, y, x, pixel2 );
                cvSet2D( lena3, y, x, pixel3 );
                cvSet2D( lena4, y, x, pixel4 );
                cvSet2D( lena5, y, x, pixel5 );
                cvSet2D( lena6, y, x, pixel6 );
                cvSet2D( lena7, y, x, pixel7 );
                cvSet2D( lena8, y, x, pixel8 );
            }
        } 
    
        //show the image
        cvShowImage( "lena1", lena1);
        cvShowImage( "lena2", lena2);
        cvShowImage( "lena3", lena3);
        cvShowImage( "lena4", lena4);
        cvShowImage( "lena5", lena5);
        cvShowImage( "lena6", lena6);
        cvShowImage( "lena7", lena7);
        cvShowImage( "lena8", lena8);
    
    /***********************************************************************************
                    we calculate the averery and std_dev
    ***********************************************************************************/
        CvScalar Avg;
        CvScalar std_dev;
    
        cvAvgSdv( lena, &Avg, &std_dev);
    
        cout<<"averege is "<<Avg.val[0]<<endl;
        cout<<"std_dev is "<<std_dev.val[0]<<endl;
    
    /************************************************************************************
                   we  convert the lena 512*512  to 2048*2048 by NN, LINEAR and CUBIC
    ************************************************************************************/
        IplImage* lena_NN        = cvCreateImage( cvSize(2048,2048), lena->depth, lena->nChannels);
        IplImage* lena_LINEAR    = cvCreateImage( cvSize(2048,2048), lena->depth, lena->nChannels);
        IplImage* lena_CUBIC    = cvCreateImage( cvSize(2048,2048), lena->depth, lena->nChannels);    
    
        cvNamedWindow("lena_NN",CV_WINDOW_NORMAL);
        cvNamedWindow("lena_LINEAR",CV_WINDOW_NORMAL);
        cvNamedWindow("lena_CUBIC",CV_WINDOW_NORMAL);
    
        cvResize(lena, lena_NN, CV_INTER_NN);
        cvResize(lena, lena_LINEAR, CV_INTER_LINEAR);
        cvResize(lena, lena_CUBIC, CV_INTER_CUBIC);
    
        cvShowImage("lena_NN",lena_NN);
        cvShowImage("lena_LINEAR",lena_LINEAR);
        cvShowImage("lena_CUBIC",lena_CUBIC);
    
    /*********************************************************************************************
                         we shear lena whose parameter is 2
    *********************************************************************************************/
        Point2f srcTri[3];  
        Point2f dstTri[3];  
        Mat rot_mat( 2, 3, CV_32FC1 );  
        Mat warp_mat( 2, 3, CV_32FC1 );  
        Mat src, warp_dst, warp_rotate_dst;  
        
        //读入图像  
        src = imread( "C:\\Users\\qiqi\\Desktop\\第一次作业[1]\\lena.bmp", 1 );  
        warp_dst = Mat::zeros( src.rows, src.cols, src.type() );  
    
        srcTri[0] = Point2f( 0,0 );  
        srcTri[1] = Point2f( src.cols - 1, 0 );  
        srcTri[2] = Point2f( 0, src.rows - 1 );  
        dstTri[0] = Point2f( src.cols*0.0, src.rows*0.0);  
        dstTri[1] = Point2f( src.cols * 0.5, src.rows*0.0 );  
        dstTri[2] = Point2f( src.cols*0.5, src.rows - 1 ); 
    
        warp_mat = getAffineTransform( srcTri, dstTri );  
        warpAffine( src, warp_dst, warp_mat, warp_dst.size() );
    
        Mat lena_shear_NN;
        Mat lena_shear_LINEAR;
        Mat lena_shear_CUBIC;
    
        cv::resize( warp_dst , lena_shear_NN,cv::Size(2048,2048),CV_INTER_NN);
        cv::resize( warp_dst , lena_shear_LINEAR,cv::Size(2048,2048),CV_INTER_LINEAR);
        cv::resize( warp_dst , lena_shear_CUBIC,cv::Size(2048,2048),CV_INTER_CUBIC);
    
        cv::namedWindow("lena_shear_NN",CV_WINDOW_NORMAL);
        cv::namedWindow("lena_shear_LINEAR",CV_WINDOW_NORMAL);
        cv::namedWindow("lena_shear_CUBIC",CV_WINDOW_NORMAL);
    
        cv::imshow("lena_shear_NN",lena_shear_NN);
        cv::imshow("lena_shear_LINEAR",lena_shear_LINEAR);
        cv::imshow("lena_shear_CUBIC",lena_shear_CUBIC);
    
    /*********************************************************************************************
     we rotated the elain Image 30 degrees and convert it to 2048*2048 by NN, LINEAR and CUBIC
    *********************************************************************************************/
        Mat elain = imread("C:\\Users\\qiqi\\Desktop\\第一次作业[1]\\elain1.bmp",1);
    
        double angle = 30  * CV_PI / 180.;
        double a = sin(angle), b = cos(angle); 
    
        int width = elain.cols;    
        int height =elain.rows;    
        int width_rotate= int(height * fabs(a) + width * fabs(b));    
        int height_rotate=int(width * fabs(a) + height * fabs(b)); 
    
        float map[6];  
        CvMat map_matrix = cv::Mat(2, 3, CV_32F, map);   
    
        CvPoint2D32f center = cvPoint2D32f(width / 2, height / 2);    
        cv2DRotationMatrix(center, 30, 1.0, &map_matrix);    
        map[2] += (width_rotate - width) / 2;    
        map[5] += (height_rotate - height) / 2;  
    
        Mat elain_rotate_NN;   
        Mat elain_rotate_LINEAR;
        Mat elain_rotate_CUBIC;
    
        Mat map_matrix1 = Mat::Mat( &map_matrix );
    
        cv::warpAffine( elain ,elain_rotate_NN, map_matrix1,cv::Size(690,690),CV_INTER_NN); 
        cv::warpAffine( elain ,elain_rotate_LINEAR, map_matrix1,cv::Size(690,690),CV_INTER_LINEAR); 
        cv::warpAffine( elain ,elain_rotate_CUBIC, map_matrix1,cv::Size(690,690),CV_INTER_CUBIC); 
    
        cv::resize( elain_rotate_NN, elain_rotate_NN, cv::Size(2048,2048),CV_INTER_NN);
        cv::resize( elain_rotate_LINEAR, elain_rotate_LINEAR, cv::Size(2048,2048),CV_INTER_LINEAR);
        cv::resize( elain_rotate_CUBIC, elain_rotate_CUBIC, cv::Size(2048,2048),CV_INTER_CUBIC);
    
        cv::namedWindow("elain_rotate_NN",CV_WINDOW_NORMAL);
        cv::namedWindow("elain_rotate_LINEAR",CV_WINDOW_NORMAL);
        cv::namedWindow("elain_rotate_CUBIC",CV_WINDOW_NORMAL);
    
        cv::imshow ("elain_rotate_NN",elain_rotate_NN);
        cv::imshow ("elain_rotate_LINEAR",elain_rotate_LINEAR);
        cv::imshow ("elain_rotate_CUBIC",elain_rotate_CUBIC);
    
    
        cv::waitKey (0);
    
        
        return 0;
    }

    八、  参考文献

    http://blog.csdn.net/fengbingchun/article/details/6408293

    http://blog.sina.com.cn/s/blog_753dfc490100vc6l.html

    http://blog.sina.com.cn/s/blog_72e198a10100sbrh.html

    http://www.opencv.org.cn/forum/viewtopic.php?t=7613

    http://blog.csdn.net/xiaowei_cqu/article/details/7616044

    这些都对我的帮助挺大的。感谢大家支持。

    PS:如果是老师搜的话,3月13号的报告可是我写的啊,绝对是原创。

    累死了,楼主歇息去了。

  • 相关阅读:
    MYSQL数据库设计规范与原则
    PHP-CI框架数据库连接默认是长连接,需要注意应用场景
    mysql性能调优与架构设计笔记
    JavaScript学习笔记
    PHP一维数组和二维数字排序整理
    MYSQL常用的Show命令笔记
    设计模式之建造者模式
    设计模式之工厂模式
    设计模式前提篇二(C++编程原则)
    设计模式前提篇一(C++/基础)
  • 原文地址:https://www.cnblogs.com/hqqxyy/p/2956476.html
Copyright © 2011-2022 走看看