精华内容
下载资源
问答
  • opencv 将两张图片显示到一幅图片

    万次阅读 2017-06-08 15:39:54
    利用OpenCV处理图片后,希望将处理后的图片和处理前的图片显示在一起,以方便看出两者之间的差别。  刚开始的想法是利用SetImageRoi和CvCopy函数,可是CvCopy函数必须要求源图片和目的图片的尺寸一致,即使设置了...

    利用OpenCV处理图片后,希望将处理后的图片和处理前的图片显示在一起,以方便看出两者之间的差别。

           刚开始的想法是利用SetImageRoi和CvCopy函数,可是CvCopy函数必须要求源图片和目的图片的尺寸一致,即使设置了Roi,由于图片的尺寸不一致,运行的时候还是会导致尺寸不匹配的错误。

           然后想到的是SetImageRoi和CvCloneImage函数,但是CvCloneImage函数运行后,会将目的图片的尺寸修改成和源图片的尺寸一致,即使设置了Roi也没有效果。

            后来看到了CvRepeat这个函数,可以完成想要的功能。

    [cpp]  view plain  copy
    1. #include <cv.h>  
    2.   
    3. #include <cxcore.h>  
    4.   
    5. #include <cassert>  
    6.   
    7. using namespace std;  
    8.   
    9. void ImageMerge(IplImage* pImageA,IplImage* pImageB,IplImage*& pImageRes)  
    10. {  
    11. assert(pImageA != NULL && pImageB != NULL);  
    12. assert(pImageA->depth == pImageB->depth && pImageA->nChannels == pImageB->nChannels);  
    13.   
    14. if (pImageRes != NULL)  
    15. {  
    16.    cvReleaseImage(&pImageRes);  
    17.    pImageRes = NULL;  
    18. }  
    19.   
    20. CvSize size;  
    21. size.width = pImageA->width + pImageB->width + 10;  
    22. size.height = (pImageA->height > pImageB->height) ? pImageA->height : pImageB->height;  
    23. pImageRes = cvCreateImage(size,pImageA->depth,pImageA->nChannels);  
    24.   
    25. CvRect rect = cvRect(0,0,pImageA->width,pImageA->height);  
    26. cvSetImageROI(pImageRes,rect);  
    27. cvRepeat(pImageA,pImageRes);  
    28. cvResetImageROI(pImageRes);  
    29. rect = cvRect(pImageA->width + 10,0,pImageB->width,pImageB->height);  
    30. cvSetImageROI(pImageRes,rect);  
    31. cvRepeat(pImageB,pImageRes);  
    32. cvResetImageROI(pImageRes);  
    33. }  



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


    在Opencv里面很多理论大家说起来都知道,也都能想到怎么做,但是真正实践起来不是那样的,可能你会经历很多次试验的失败,再到睡觉都思索时候你也还是失败,然后洗把脸继续钻研,一行一行钻研,做笔记,画图,后来发现OK了。这也就是研究的乐趣。哈哈哈。不说这么多废话。开始记录技术点。


    图片合成:


    注意:


    1:如果你是两张合并的图片大小尺寸和深度都一样,那随便用那个方法都行。

         cvAdd(pCutPic,pBgImage, pBgImage, NULL);   (参数IplImage*方式贴)

         这个是两个图片像素的叠加,会有两个像素区域加起来颜色太亮,或者太暗。但是如果两幅图其中有一个是

         透明的也无所谓。

          cutROIMat.copyTo(bgROIMat);  (参数Mat直接拷贝)

          cutROIMat.copyTo(bgROIMat,cutROIGrayMask); (参数Mat直接拷贝)

          addWeighted(bgROIMat, 0.5, cutROIMat, 0.5, 0, bgROIMat); 这个能调节两幅图的alpha合成比例。  (参数 Mat直接拷贝)

    2:两幅大小不同图片合成,且在另一幅上扣除一块区域合成。

          A:这里需要注意的就是先从一副图上取出那块区域生成一个小的mat图,

                Mat cutROIMat = srcCutPic(Rect

                                               (mBoardRect.x,mBoardRect.y,mBoardRect.width,mBoardRect.height));

                 //把要扣出来的内容取出来作为小图。

          B:然后目标图片指定贴上去的区域。

              Mat bgROIMat = mBGImage(Rect

               (mBoardRect.x,mBoardRect.y,mBoardRect.width,mBoardRect.height));

               //注意必须在要贴的大图上指定感兴趣区域。

          C:把这个cutROIMat 作为源小图贴在bgROIMat 上。

                 cutROIMat.copyTo(bgROIMat); //也是可以的,只是有黑色矩形框。

                 cutROIMat.copyTo(bgROIMat,cutROIGrayMask);  这个是去掉黑色边缘。

                 addWeighted(bgROIMat, 0.5, cutROIMat, 0.5, 0, bgROIMat); 这个是调节两个图的alpha合成。避免

                 合成区域变色。

    注意: srcCutPic= imread("D:\\test.jpg");
               mBGImage = imread("D:\\view.jpg");   这个是自己写的,不是全部代码。只是将理论。自己做笔记备注。


    3:如果是两幅图片大小尺寸不一样的。必须在要贴上去的图片上指定ROI,细节:目标图片的ROI的Rect必须 

          是准备贴上去图的区域或者大小。      如下就行:

    C++: void Mat::copyTo(OutputArraym)const

    C++: void  Mat:: copyTo (OutputArray m, InputArray mask ) const 这个函数可以复制图像到另一个图像或矩阵上,可选参数是掩码 由于叠加的图像大小不一定相等,比如我们这里把一张小照片加到一张大照片上 我们可以在大照片上设置一个和小照片一样大的感兴趣区域 不使用掩码的时候,我们载入一张png,和一张jpg


    #include <</SPAN>opencv2/highgui/highgui.hpp>
     #include <</SPAN>opencv2/core/core.hpp>
     
    int main(){
    cv::Mat image = cv::imread("E:/Image/Fruits.jpg");
    cv::Mat logo = cv::imread("E:/logo.png");
    cv::Mat imageROI;
    imageROI = image(cv::Rect(10,10,logo.cols,logo.rows));
    logo.copyTo(imageROI);
    cv::namedWindow("result");
    cv::imshow("result",image);
    cv::waitKey();
     return 0;
    } 



    原先在png里面是透明的地方,现在成了黑色,可见原来是透明的地方被认为是值0。 我们使用掩码来看看效果,掩码就使用png图片,掩码只能是一个通道的,我们载入灰度图像作为掩码


    #include <</SPAN>opencv2/highgui/highgui.hpp>
     #include <</SPAN>opencv2/core/core.hpp>
     
    int main(){
    cv::Mat image = cv::imread("E:/Image/Fruits.jpg");
    cv::Mat logo = cv::imread("E:/logo.png");
    cv::Mat mask = cv::imread("E:/logo.png",0);
    cv::Mat imageROI;
    imageROI = image(cv::Rect(10,10,logo.cols,logo.rows));
    logo.copyTo(imageROI,mask);
    cv::namedWindow("result");
    cv::imshow("result",image);
    cv::waitKey();
     return 0;
    } 



    这样能看出差别了吧。 再来看看另一个函数 C++: void  addWeighted (InputArray src1, double alpha, InputArray  src2, double beta, double gamma, OutputArray  dst, int dtype=-1 ) 转换成数学表达式就是


    #include <</SPAN>opencv2/highgui/highgui.hpp>
     #include <</SPAN>opencv2/core/core.hpp>
     
    int main(){
    cv::Mat image = cv::imread("E:/Image/Fruits.jpg");
    cv::Mat logo = cv::imread("E:/logo.png");
    cv::Mat imageROI;
    imageROI = image(cv::Rect(10,10,logo.cols,logo.rows));
    cv::addWeighted(imageROI, 1.0, logo, 0.3, 0, imageROI);
    cv::namedWindow("result");
    cv::imshow("result",image);
    cv::waitKey();
     return 0;
    } 



    http://blog.csdn.net/poem_qianmo/article/details/20911629


     

    本系列文章由@浅墨_毛星云 出品,转载请注明出处。  

    文章链接: http://blog.csdn.net/poem_qianmo/article/details/20911629

    作者:毛星云(浅墨)    邮箱: happylifemxy@163.com 

    写作当前博文时配套使用的OpenCV版本: 2.4.8


     

    在这篇文章里,我们一起学习了在OpenCV中如何定义感兴趣区域ROI,如何使用addWeighted函数进行图像混合操作,以及将ROI和addWeighted函数结合起来使用,对指定区域进行图像混合操作。

    PS:文章末尾提供了博文配套程序源代码的下载。


    文章开头,依旧是先放一张截图:


     

     





    一、设定感兴趣区域——ROI(region of interest)




    在图像处理领域,我们常常需要设置感兴趣区域(ROI,region of interest),来专注或者简化我们的工作过程 。也就是从图像中选择的一个图像区域,这个区域是我们图像分析所关注的重点。我们圈定这个区域,以便进行进一步处理。而且,使用ROI指定我们想读入的目标,可以减少处理时间,增加精度,给图像处理来带不小的便利。

     

     


    ROI区域定义的两种方法

     


    定义ROI区域有两种方法,第一种是使用cv:Rect.顾名思义,cv::Rect表示一个矩形区域。指定矩形的左上角坐标(构造函数的前两个参数)和矩形的长宽(构造函数的后两个参数)就可以定义一个矩形区域。

     

    [cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
    1. //定义一个Mat类型并给其设定ROI区域  
    2. Mat imageROI;  
    3. //方法一  
    4. imageROI=image(Rect(500,250,logo.cols,logo.rows));  


    另一种定义ROI的方式是指定感兴趣行或列的范围(Range)。Range是指从起始索引到终止索引(不包括终止索引)的一连段连续序列。cv::Range可以用来定义Range。如果使用cv::Range来定义ROI,那么前例中定义ROI的代码可以重写为:

    [cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
    1. //方法二  
    2. imageROI=srcImage3(Range(250,250+logoImage.rows),Range(200,200+logoImage.cols));  


    好了,下面我们来看一个实例,显示如何利用ROI将一幅图加到另一幅图的指定位置。大家如果需要拷贝如下的函数中的代码直接运行的话,自己建一个基于console的程序,然后把函数体中的内容拷贝到main函数中,然后找两幅大小合适的图片,加入到工程目录下,并和代码中读取的文件名一致即可。

    在下面的代码中,我们通过一个图像掩膜(mask),直接将插入处的像素设置为logo图像的像素值,这样效果会很赞很逼真:

     

    [cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
    1. //----------------------------------【ROI_AddImage( )函数】----------------------------------  
    2. // 函数名:ROI_AddImage()  
    3. //     描述:利用感兴趣区域ROI实现图像叠加  
    4. //----------------------------------------------------------------------------------------------  
    5. bool ROI_AddImage()  
    6. {  
    7.    
    8.        //【1】读入图像  
    9.        Mat srcImage1= imread("dota_pa.jpg");  
    10.        Mat logoImage= imread("dota_logo.jpg");  
    11.        if(!srcImage1.data ) { printf("你妹,读取srcImage1错误~! \n"); return false; }  
    12.        if(!logoImage.data ) { printf("你妹,读取logoImage错误~! \n"); return false; }  
    13.    
    14.        //【2】定义一个Mat类型并给其设定ROI区域  
    15.        Mat imageROI= srcImage1(Rect(200,250,logoImage.cols,logoImage.rows));  
    16.    
    17.        //【3】加载掩模(必须是灰度图)  
    18.        Mat mask= imread("dota_logo.jpg",0);  
    19.    
    20.        //【4】将掩膜拷贝到ROI  
    21.        logoImage.copyTo(imageROI,mask);  
    22.    
    23.        //【5】显示结果  
    24.        namedWindow("<1>利用ROI实现图像叠加示例窗口");  
    25.        imshow("<1>利用ROI实现图像叠加示例窗口",srcImage1);  
    26.    
    27.        return true;  
    28. }  


    这个函数首先是载入了两张jpg图片到srcImage1和logoImage中,然后定义了一个Mat类型的imageROI,并使用cv::Rect设置其感兴趣区域为srcImage1中的一块区域,将imageROI和srcImage1关联起来。接着定义了一个Mat类型的的mask并读入dota_logo.jpg,顺势使用Mat:: copyTo把mask中的内容拷贝到imageROI中,于是就得到了最终的效果图,namedWindow和imshow配合使用,显示出最终的结果。


    运行结果如下:


     

    这里白色的dota2 logo,就是通过操作之后加上去的图像。

     

     

     



     

    二、初级图像混合——线性混合操作

     



     

    线性混合操作是一种典型的二元(两个输入)的像素操作,它的理论公式是这样的:

      

                                                                  

     

    如果看过我之前写的游戏编程Alpha混合那篇文章的朋友们应该有些熟悉,其实他们是差不多的:

     

    【Visual C++】游戏开发五十五浅墨 DirectX教程二十二水乳交融的美学:alpha混合技术


     

    我们通过在范围0到1之间改变alpha值,来对两幅图像(f0(x)和f1(x))或两段视频(同样为(f0(x)和f1(x))产生时间上的画面叠化(cross-dissolve)效果,就像幻灯片放映和电影制作中的那样。即在幻灯片翻页时设置的前后页缓慢过渡叠加效果,以及电影情节过渡时经常出现的画面叠加效果。

    实现方面,我们主要运用了OpenCV中addWeighted函数,我们来全面的了解一下它:

     


    addWeighted函数


    这个函数的作用是,计算两个数组(图像阵列)的加权和。原型如下:

     

    [cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
    1. void addWeighted(InputArray src1, double alpha, InputArray src2, double beta, double gamma, OutputArray dst, int dtype=-1);  

    • 第一个参数,InputArray类型的src1,表示需要加权的第一个数组,常常填一个Mat。
    • 第二个参数,alpha,表示第一个数组的权重
    • 第三个参数,src2,表示第二个数组,它需要和第一个数组拥有相同的尺寸和通道数。
    • 第四个参数,beta,表示第二个数组的权重值。
    • 第五个参数,dst,输出的数组,它和输入的两个数组拥有相同的尺寸和通道数。
    • 第六个参数,gamma,一个加到权重总和上的标量值。看下面的式子自然会理解。
    • 第七个参数,dtype,输出阵列的可选深度,有默认值-1。;当两个输入数组具有相同的深度时,这个参数设置为-1(默认值),即等同于src1.depth()。

     

    如果用数学公式来表达,addWeighted函数计算如下两个数组(src1和src2)的加权和,得到结果输出给第四个参数。即addWeighted函数的作用可以被表示为为如下的矩阵表达式为:

     

                                                          dst = src1[I]*alpha+ src2[I]*beta + gamma;

     

    其中的I,是多维数组元素的索引值。而且,在遇到多通道数组的时候,每个通道都需要独立地进行处理。另外需要注意的是,当输出数组的深度为CV_32S时,这个函数就不适用了,这时候就会内存溢出或者算出的结果压根不对。

     

     

    理论和函数的讲解就是上面这些,接着我们来看代码实例,以融会贯通。

     

    [cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
    1. //---------------------------------【LinearBlending()函数】-------------------------------------  
    2. // 函数名:LinearBlending()  
    3. // 描述:利用cv::addWeighted()函数实现图像线性混合  
    4. //--------------------------------------------------------------------------------------------  
    5. bool LinearBlending()  
    6. {  
    7.        //【0】定义一些局部变量  
    8.        double alphaValue = 0.5;  
    9.        double betaValue;  
    10.        Mat srcImage2, srcImage3, dstImage;  
    11.    
    12.        //【1】读取图像 ( 两幅图片需为同样的类型和尺寸 )  
    13.        srcImage2= imread("mogu.jpg");  
    14.        srcImage3= imread("rain.jpg");  
    15.    
    16.        if(!srcImage2.data ) { printf("你妹,读取srcImage2错误~! \n"); return false; }  
    17.        if(!srcImage3.data ) { printf("你妹,读取srcImage3错误~! \n"); return false; }  
    18.    
    19.        //【2】做图像混合加权操作  
    20.        betaValue= ( 1.0 - alphaValue );  
    21.        addWeighted(srcImage2, alphaValue, srcImage3, betaValue, 0.0, dstImage);  
    22.    
    23.        //【3】创建并显示原图窗口  
    24.        namedWindow("<2>线性混合示例窗口【原图】 by浅墨", 1);  
    25.        imshow("<2>线性混合示例窗口【原图】 by浅墨", srcImage2 );  
    26.    
    27.        namedWindow("<3>线性混合示例窗口【效果图】 by浅墨", 1);  
    28.        imshow("<3>线性混合示例窗口【效果图】 by浅墨", dstImage );  
    29.    
    30.        return true;  
    31.         
    32. }  



    代码解析:


    <0>首先当然是定义一些局部变量,alpha值beta值,三个Mat类型的变量。

     

    [cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
    1. //【0】定义一些局部变量  
    2.        double alphaValue = 0.5;  
    3.        double betaValue;  
    4.        Mat srcImage2, srcImage3, dstImage;  

           

    在这里我们设置alpha值为0.5。

     

    <1>读取两幅图像并作错误处理

    这步很简单,直接上代码:

           

    [cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
    1. //读取图像 ( 两幅图片需为同样的类型和尺寸 )  
    2.        srcImage2= imread("mogu.jpg");  
    3.        srcImage3= imread("rain.jpg");  
    4. if(!srcImage2.data ) { printf("你妹,读取srcImage2错误~! \n"); return false; }  
    5.        if(!srcImage3.data ) { printf("你妹,读取srcImage3错误~! \n"); return false; }  


    在这里需要注意的是,因为我们是对 srcImage1和srcImage2求和,所以它们必须要有相同的尺寸(宽度和高度)和类型,不然多余的部分没有对应的“伴”,肯定会出问题。


    <2> 进行图像混合加权操作

    载入图像后,我们就可以来生成混合图像,也就是之前公式中的g(x)。为此目的,使用函数 addWeighted 可以很方便地实现,也就是因为 addWeighted 进行了如下计算:

     

    这里的对应于addWeighted的第2个参数alpha

    这里的对应于addWeighted的第4个参数beta

    这里的对应于addWeighted的第5个参数,在上面代码中被我们设为0.0。

    代码其实很简单,就是这样: 

    [cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
    1. //【2】进行图像混合加权操作  
    2.   betaValue = ( 1.0 - alphaValue );  
    3.   addWeighted( srcImage2, alphaValue, srcImage3,betaValue, 0.0, dstImage);  
    4. 其中beta值为1-alpha,gamma值为0。  


    <3>创建显示窗口,显示图像。

    [cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
    1. // 【3】创建并显示原图窗口  
    2.        namedWindow("<2>线性混合示例窗口【原图】 by浅墨", 1);  
    3.        imshow("<2>线性混合示例窗口【原图】 by浅墨", srcImage2 );  
    4.    
    5.        namedWindow("<3>线性混合示例窗口【效果图】 by浅墨", 1);  
    6.        imshow("<3>线性混合示例窗口【效果图】 by浅墨", dstImage );  


    接着来看一下运行效果图,首先是原图:



    然后是效果图:

     

     





    三、综合示例

     



    在前面分别介绍的设定感兴趣区域ROI和使用addWeighted函数进行图像线性混合的基础上,我们还将他们两者中和起来使用,也就是先指定ROI,并用addWeighted函数对我们指定的ROI区域的图像进行混合操作,我们将其封装在了一个名为ROI_LinearBlending的函数中,方便大家分块学习。

     


    [cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
    1. //---------------------------------【ROI_LinearBlending()】-------------------------------------  
    2. // 函数名:ROI_LinearBlending()  
    3. // 描述:线性混合实现函数,指定区域线性图像混合.利用cv::addWeighted()函数结合定义  
    4. //                     感兴趣区域ROI,实现自定义区域的线性混合  
    5. //--------------------------------------------------------------------------------------------  
    6. bool ROI_LinearBlending()  
    7. {  
    8.    
    9.        //【1】读取图像  
    10.        Mat srcImage4= imread("dota_pa.jpg",1);  
    11.        Mat logoImage= imread("dota_logo.jpg");  
    12.    
    13.        if(!srcImage4.data ) { printf("你妹,读取srcImage4错误~! \n"); return false; }  
    14.        if(!logoImage.data ) { printf("你妹,读取logoImage错误~! \n"); return false; }  
    15.    
    16.        //【2】定义一个Mat类型并给其设定ROI区域  
    17.        Mat imageROI;  
    18.               //方法一  
    19.        imageROI=srcImage4(Rect(200,250,logoImage.cols,logoImage.rows));  
    20.        //方法二  
    21.        //imageROI=srcImage4(Range(250,250+logoImage.rows),Range(200,200+logoImage.cols));  
    22.    
    23.        //【3】将logo加到原图上  
    24.        addWeighted(imageROI,0.5,logoImage,0.3,0.,imageROI);  
    25.    
    26.        //【4】显示结果  
    27.        namedWindow("<4>区域线性图像混合示例窗口 by浅墨");  
    28.        imshow("<4>区域线性图像混合示例窗口 by浅墨",srcImage4);  
    29.         
    30.        return true;  
    31. }  



    从这篇文章开始,如果不出意外的话,为了方便大家分块各个击破学习,每讲一个部分,示例代码都将封装在一个函数中,免得大家像学习各种不是特别地道的OpenCV教程时一样,看到代码全放在main函数中,心都碎了。

     

    好了,下面放出详细注释的本篇文章的全部示例源代码:

     

    [cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
    1. //-----------------------------------【程序说明】----------------------------------------------  
    2. //  程序名称::【OpenCV入门教程之四】 ROI区域图像叠加&初级图像混合 全剖析   配套源码  
    3. // VS2010版   OpenCV版本:2.4.8  
    4. //     2014年3月10日 Create by 浅墨  
    5. //    图片素材出处:dota2原画 dota2logo   
    6. //     浅墨的微博:@浅墨_毛星云  
    7. //------------------------------------------------------------------------------------------------  
    8.    
    9. //-----------------------------------【头文件包含部分】---------------------------------------  
    10. //     描述:包含程序所依赖的头文件  
    11. //----------------------------------------------------------------------------------------------                                                                                      
    12. #include <cv.h>  
    13. #include <highgui.h>  
    14. #include <iostream>  
    15.    
    16. //-----------------------------------【命名空间声明部分】---------------------------------------  
    17. //     描述:包含程序所使用的命名空间  
    18. //-----------------------------------------------------------------------------------------------    
    19. using namespace cv;  
    20. using namespace std;  
    21.    
    22.    
    23. //-----------------------------------【全局函数声明部分】--------------------------------------  
    24. //     描述:全局函数声明  
    25. //-----------------------------------------------------------------------------------------------  
    26. bool ROI_AddImage();  
    27. bool LinearBlending();  
    28. bool ROI_LinearBlending();  
    29.    
    30. //-----------------------------------【main( )函数】--------------------------------------------  
    31. //     描述:控制台应用程序的入口函数,我们的程序从这里开始  
    32. //-----------------------------------------------------------------------------------------------  
    33. int main(  )  
    34. {  
    35.        system("color 5E");  
    36.    
    37.        if(ROI_AddImage()&& LinearBlending( )&&ROI_LinearBlending( ))  
    38.        {  
    39.               cout<<endl<<"嗯。好了,得出了你需要的图像~! : )";  
    40.        }  
    41.    
    42.        waitKey(0);  
    43.        return 0;  
    44. }  
    45.    
    46. //----------------------------------【ROI_AddImage( )函数】----------------------------------  
    47. // 函数名:ROI_AddImage()  
    48. //     描述:利用感兴趣区域ROI实现图像叠加  
    49. //----------------------------------------------------------------------------------------------  
    50. bool ROI_AddImage()  
    51. {  
    52.    
    53.        //【1】读入图像  
    54.        Mat srcImage1= imread("dota_pa.jpg");  
    55.        Mat logoImage= imread("dota_logo.jpg");  
    56.        if(!srcImage1.data ) { printf("你妹,读取srcImage1错误~! \n"); return false; }  
    57.        if(!logoImage.data ) { printf("你妹,读取logoImage错误~! \n"); return false; }  
    58.    
    59.        //【2】定义一个Mat类型并给其设定ROI区域  
    60.        Mat imageROI= srcImage1(Rect(200,250,logoImage.cols,logoImage.rows));  
    61.    
    62.        //【3】加载掩模(必须是灰度图)  
    63.        Mat mask= imread("dota_logo.jpg",0);  
    64.    
    65.        //【4】将掩膜拷贝到ROI  
    66.        logoImage.copyTo(imageROI,mask);  
    67.    
    68.        //【5】显示结果  
    69.        namedWindow("<1>利用ROI实现图像叠加示例窗口");  
    70.        imshow("<1>利用ROI实现图像叠加示例窗口",srcImage1);  
    71.    
    72.        return true;  
    73. }  
    74.    
    75.    
    76. //---------------------------------【LinearBlending()函数】-------------------------------------  
    77. // 函数名:LinearBlending()  
    78. // 描述:利用cv::addWeighted()函数实现图像线性混合  
    79. //--------------------------------------------------------------------------------------------  
    80. bool LinearBlending()  
    81. {  
    82.        //【0】定义一些局部变量  
    83.        double alphaValue = 0.5;  
    84.        double betaValue;  
    85.        Mat srcImage2, srcImage3, dstImage;  
    86.    
    87.        //【1】读取图像 ( 两幅图片需为同样的类型和尺寸 )  
    88.        srcImage2= imread("mogu.jpg");  
    89.        srcImage3= imread("rain.jpg");  
    90.    
    91.        if(!srcImage2.data ) { printf("你妹,读取srcImage2错误~! \n"); return false; }  
    92.        if(!srcImage3.data ) { printf("你妹,读取srcImage3错误~! \n"); return false; }  
    93.    
    94.        //【2】进行图像混合加权操作  
    95.        betaValue= ( 1.0 - alphaValue );  
    96.        addWeighted(srcImage2, alphaValue, srcImage3, betaValue, 0.0, dstImage);  
    97.    
    98.        //【3】创建并显示原图窗口  
    99.        namedWindow("<2>线性混合示例窗口【原图】 by浅墨", 1);  
    100.        imshow("<2>线性混合示例窗口【原图】 by浅墨", srcImage2 );  
    101.    
    102.        namedWindow("<3>线性混合示例窗口【效果图】 by浅墨", 1);  
    103.        imshow("<3>线性混合示例窗口【效果图】 by浅墨", dstImage );  
    104.    
    105.        return true;  
    106.         
    107. }  
    108.    
    109. //---------------------------------【ROI_LinearBlending()】-------------------------------------  
    110. // 函数名:ROI_LinearBlending()  
    111. // 描述:线性混合实现函数,指定区域线性图像混合.利用cv::addWeighted()函数结合定义  
    112. //                     感兴趣区域ROI,实现自定义区域的线性混合  
    113. //--------------------------------------------------------------------------------------------  
    114. bool ROI_LinearBlending()  
    115. {  
    116.    
    117.        //【1】读取图像  
    118.        Mat srcImage4= imread("dota_pa.jpg",1);  
    119.        Mat logoImage= imread("dota_logo.jpg");  
    120.    
    121.        if(!srcImage4.data ) { printf("你妹,读取srcImage4错误~! \n"); return false; }  
    122.        if(!logoImage.data ) { printf("你妹,读取logoImage错误~! \n"); return false; }  
    123.    
    124.        //【2】定义一个Mat类型并给其设定ROI区域  
    125.        Mat imageROI;  
    126.               //方法一  
    127.        imageROI=srcImage4(Rect(200,250,logoImage.cols,logoImage.rows));  
    128.        //方法二  
    129.        //imageROI=srcImage4(Range(250,250+logoImage.rows),Range(200,200+logoImage.cols));  
    130.    
    131.        //【3】将logo加到原图上  
    132.        addWeighted(imageROI,0.5,logoImage,0.3,0.,imageROI);  
    133.    
    134.        //【4】显示结果  
    135.        namedWindow("<4>区域线性图像混合示例窗口 by浅墨");  
    136.        imshow("<4>区域线性图像混合示例窗口 by浅墨",srcImage4);  
    137.         
    138.        return true;  
    139. }  


    最后看一下整体的运行效果图。

    首先是经过背景颜色修改的console窗口:



    然后依次是四张效果图:









     嗯,本篇文章到这里就基本结束了,最后放出本篇文章配套示例程序的下载地址。


    展开全文
  • 图像分割综述

    万次阅读 多人点赞 2019-07-09 22:03:48
    图像分割是计算机视觉研究中的个经典难题,已经成为图像理解领域关注的个热点,图像分割是图像分析的第步,是计算机视觉的基础,是图像理解的重要组成部分,同时也是图像处理中最困难的问题之。所谓图像分割...

    本文作者净浩泽,公众号:计算机视觉life,编辑成员

    图像分割是计算机视觉研究中的一个经典难题,已经成为图像理解领域关注的一个热点,图像分割是图像分析的第一步,是计算机视觉的基础,是图像理解的重要组成部分,同时也是图像处理中最困难的问题之一。所谓图像分割是指根据灰度、彩色、空间纹理、几何形状等特征把图像划分成若干个互不相交的区域,使得这些特征在同一区域内表现出一致性或相似性,而在不同区域间表现出明显的不同。简单的说就是在一副图像中,把目标从背景中分离出来。对于灰度图像来说,区域内部的像素一般具有灰度相似性,而在区域的边界上一般具有灰度不连续性。 关于图像分割技术,由于问题本身的重要性和困难性,从20世纪70年代起图像分割问题就吸引了很多研究人员为之付出了巨大的努力。虽然到目前为止,还不存在一个通用的完美的图像分割的方法,但是对于图像分割的一般性规律则基本上已经达成的共识,已经产生了相当多的研究成果和方法。

    本文对于目前正在使用的各种图像分割方法进行了一定的归纳总结,由于笔者对于图像分割的了解也是初窥门径,所以难免会有一些错误,还望各位读者多多指正,共同学习进步。

    传统分割方法

    这一大部分我们将要介绍的是深度学习大火之前人们利用数字图像处理、拓扑学、数学等方面的只是来进行图像分割的方法。当然现在随着算力的增加以及深度学习的不断发展,一些传统的分割方法在效果上已经不能与基于深度学习的分割方法相比较了,但是有些天才的思想还是非常值得我们去学习的。
    1.基于阈值的分割方法
    阈值法的基本思想是基于图像的灰度特征来计算一个或多个灰度阈值,并将图像中每个像素的灰度值与阈值作比较,最后将像素根据比较结果分到合适的类别中。因此,该方法最为关键的一步就是按照某个准则函数来求解最佳灰度阈值。
    阈值法特别适用于目标和背景占据不同灰度级范围的图。
    图像若只有目标和背景两大类,那么只需要选取一个阈值进行分割,此方法成为单阈值分割;但是如果图像中有多个目标需要提取,单一阈值的分割就会出现作物,在这种情况下就需要选取多个阈值将每个目标分隔开,这种分割方法相应的成为多阈值分割。

    如图所示即为对数字的一种阈值分割方法。
    阀值分割方法的优缺点:

    • 计算简单,效率较高;
    • 只考虑像素点灰度值本身的特征,一般不考虑空间特征,因此对噪声比较敏感,鲁棒性不高。
      从前面的介绍里我们可以看出,阈值分割方法的最关键就在于阈值的选择。若将智能遗传算法应用在阀值筛选上,选取能最优分割图像的阀值,这可能是基于阀值分割的图像分割法的发展趋势。
      2.基于区域的图像分割方法
      基于区域的分割方法是以直接寻找区域为基础的分割技术,基于区域提取方法有两种基本形式:一种是区域生长,从单个像素出发,逐步合并以形成所需要的分割区域;另一种是从全局出发,逐步切割至所需的分割区域。
      区域生长
      区域生长是从一组代表不同生长区域的种子像素开始,接下来将种子像素邻域里符合条件的像素合并到种子像素所代表的生长区域中,并将新添加的像素作为新的种子像素继续合并过程,知道找不到符合条件的新像素为止(小编研一第一学期的机器学习期末考试就是手写该算法 T.T),该方法的关键是选择合适的初始种子像素以及合理的生长准则。
      区域生长算法需要解决的三个问题:
      (1)选择或确定一组能正确代表所需区域的种子像素;
      (2)确定在生长过程中能将相邻像素包括进来的准则;
      (3)指定让生长过程停止的条件或规则。
      区域分裂合并
      区域生长是从某个或者某些像素点出发,最终得到整个区域,进而实现目标的提取。而分裂合并可以说是区域生长的逆过程,从整幅图像出发,不断的分裂得到各个子区域,然后再把前景区域合并,得到需要分割的前景目标,进而实现目标的提取。其实如果理解了上面的区域生长算法这个区域分裂合并算法就比较好理解啦。
      四叉树分解法就是一种典型的区域分裂合并法,基本算法如下:
      (1)对于任一区域,如果H(Ri)=FALSE就将其分裂成不重叠的四等分;
      (2)对相邻的两个区域Ri和Rj,它们也可以大小不同(即不在同一层),如果条件H(RiURj)=TURE满足,就将它们合并起来;
      (3)如果进一步的分裂或合并都不可能,则结束。
      其中R代表整个正方形图像区域,P代表逻辑词。
      区域分裂合并算法优缺点:
      (1)对复杂图像分割效果好;
      (2)算法复杂,计算量大;
      (3)分裂有可能破怪区域的边界。
      在实际应用当中通常将区域生长算法和区域分裂合并算法结合使用,该类算法对某些复杂物体定义的复杂场景的分割或者对某些自然景物的分割等类似先验知识不足的图像分割效果较为理想。
      分水岭算法
      分水岭算法是一个非常好理解的算法,它根据分水岭的构成来考虑图像的分割,现实中我们可以想象成有山和湖的景象,那么一定是如下图的,水绕山山围水的景象。
      分水岭分割方法,是一种基于拓扑理论的数学形态学的分割方法,其基本思想是把图像看作是测地学上的拓扑地貌,图像中每一点像素的灰度值表示该点的海拔高度,每一个局部极小值及其影响区域称为集水盆,而集水盆的边界则形成分水岭。分水岭的概念和形成可以通过模拟浸入过程来说明。在每一个局部极小值表面,刺穿一个小孔,然后把整个模型慢慢浸入水中,随着浸入的加深,每一个局部极小值的影响域慢慢向外扩展,在两个集水盆汇合处构筑大坝,即形成分水岭。
      分水岭对微弱边缘具有良好的响应,图像中的噪声、物体表面细微的灰度变化都有可能产生过度分割的现象,但是这也同时能够保证得到封闭连续边缘。同时,分水岭算法得到的封闭的集水盆也为分析图像的区域特征提供了可能。

    3.基于边缘检测的分割方法

    基于边缘检测的图像分割算法试图通过检测包含不同区域的边缘来解决分割问题。它可以说是人们最先想到也是研究最多的方法之一。通常不同区域的边界上像素的灰度值变化比较剧烈,如果将图片从空间域通过傅里叶变换到频率域,边缘就对应着高频部分,这是一种非常简单的边缘检测算法。
    边缘检测技术通常可以按照处理的技术分为串行边缘检测和并行边缘检测。串行边缘检测是要想确定当前像素点是否属于检测边缘上的一点,取决于先前像素的验证结果。并行边缘检测是一个像素点是否属于检测边缘高尚的一点取决于当前正在检测的像素点以及与该像素点的一些临近像素点。
    最简单的边缘检测方法是并行微分算子法,它利用相邻区域的像素值不连续的性质,采用一阶或者二阶导数来检测边缘点。近年来还提出了基于曲面拟合的方法、基于边界曲线拟合的方法、基于反应-扩散方程的方法、串行边界查找、基于变形模型的方法。

    边缘检测的优缺点:
    (1)边缘定位准确;
    (2)速度快;
    (3)不能保证边缘的连续性和封闭性;
    (4)在高细节区域存在大量的碎边缘,难以形成一个大区域,但是又不宜将高细节区域分成小碎片;
    由于上述的(3)(4)两个难点,边缘检测只能产生边缘点,而非完整意义上的图像分割过程。这也就是说,在边缘点信息获取到之后还需要后续的处理或者其他相关算法相结合才能完成分割任务。
    在以后的研究当中,用于提取初始边缘点的自适应阈值选取、用于图像的层次分割的更大区域的选取以及如何确认重要边缘以去除假边缘将变得非常重要。

    结合特定工具的图像分割算法

    基于小波分析和小波变换的图像分割方法

    小波变换是近年来得到的广泛应用的数学工具,也是现在数字图像处理必学部分,它在时间域和频率域上都有量高的局部化性质,能将时域和频域统一于一体来研究信号。而且小波变换具有多尺度特性,能够在不同尺度上对信号进行分析,因此在图像分割方面的得到了应用,
    二进小波变换具有检测二元函数的局部突变能力,因此可作为图像边缘检测工具。图像的边缘出现在图像局部灰度不连续处,对应于二进小波变换的模极大值点。通过检测小波变换模极大值点可以确定图像的边缘小波变换位于各个尺度上,而每个尺度上的小波变换都能提供一定的边缘信息,因此可进行多尺度边缘检测来得到比较理想的图像边缘。

    上图左图是传统的阈值分割方法,右边的图像就是利用小波变换的图像分割。可以看出右图分割得到的边缘更加准确和清晰
    另外,将小波和其他方法结合起来处理图像分割的问题也得到了广泛研究,比如一种局部自适应阈值法就是将Hilbert图像扫描和小波相结合,从而获得了连续光滑的阈值曲线。

    基于遗传算法的图像分割

    ​ 遗传算法(Genetic Algorithms,简称GA)是1973年由美国教授Holland提出的,是一种借鉴生物界自然选择和自然遗传机制的随机化搜索算法。是仿生学在数学领域的应用。其基本思想是,模拟由一些基因串控制的生物群体的进化过程,把该过程的原理应用到搜索算法中,以提高寻优的速度和质量。此算法的搜索过程不直接作用在变量上,而是在参数集进行了编码的个体,这使得遗传算法可直接对结构对象(图像)进行操作。整个搜索过程是从一组解迭代到另一组解,采用同时处理群体中多个个体的方法,降低了陷入局部最优解的可能性,并易于并行化。搜索过程采用概率的变迁规则来指导搜索方向,而不采用确定性搜索规则,而且对搜索空间没有任何特殊要求(如连通性、凸性等),只利用适应性信息,不需要导数等其他辅助信息,适应范围广。
    ​ 遗传算法擅长于全局搜索,但局部搜索能力不足,所以常把遗传算法和其他算法结合起来应用。将遗传算法运用到图像处理主要是考虑到遗传算法具有与问题领域无关且快速随机的搜索能力。其搜索从群体出发,具有潜在的并行性,可以进行多个个体的同时比较,能有效的加快图像处理的速度。但是遗传算法也有其缺点:搜索所使用的评价函数的设计、初始种群的选择有一定的依赖性等。要是能够结合一些启发算法进行改进且遗传算法的并行机制的潜力得到充分的利用,这是当前遗传算法在图像处理中的一个研究热点。

    基于主动轮廓模型的分割方法

    ​ 主动轮廓模型(active contours)是图像分割的一种重要方法,具有统一的开放式的描述形式,为图像分割技术的研究和创新提供了理想的框架。在实现主动轮廓模型时,可以灵活的选择约束力、初始轮廓和作用域等,以得到更佳的分割效果,所以主动轮廓模型方法受到越来越多的关注。
    ​ 该方法是在给定图像中利用曲线演化来检测目标的一类方法,基于此可以得到精确的边缘信息。其基本思想是,先定义初始曲线C,然后根据图像数据得到能量函数,通过最小化能量函数来引发曲线变化,使其向目标边缘逐渐逼近,最终找到目标边缘。这种动态逼近方法所求得的边缘曲线具有封闭、光滑等优点。

    ​ 传统的主动轮廓模型大致分为参数主动轮廓模型和几何主动轮廓模型。参数主动轮廓模型将曲线或曲面的形变以参数化形式表达,Kass等人提出了经典的参数活动轮廓模型即“Snake”模型,其中Snake定义为能量极小化的样条曲线,它在来自曲线自身的内力和来自图像数据的外力的共同作用下移动到感兴趣的边缘,内力用于约束曲线形状,而外力则引导曲线到特征此边缘。参数主动轮廓模型的特点是将初始曲线置于目标区域附近,无需人为设定曲线的的演化是收缩或膨胀,其优点是能够与模型直接进行交互,且模型表达紧凑,实现速度快;其缺点是难以处理模型拓扑结构的变化。比如曲线的合并或分裂等。而使用水平集(level set)的几何活动轮廓方法恰好解决了这一问题。

    基于深度学习的分割

    1.基于特征编码(feature encoder based)

    在特征提取领域中VGGnet和ResNet是两个非常有统治力的方法,接下来的一些篇幅会对这两个方法进行简短的介绍

    a.VGGNet

    ​ 由牛津大学计算机视觉组合和Google DeepMind公司研究员一起研发的深度卷积神经网络。它探索了卷积神经网络的深度和其性能之间的关系,通过反复的堆叠33的小型卷积核和22的最大池化层,成功的构建了16~19层深的卷积神经网络。VGGNet获得了ILSVRC 2014年比赛的亚军和定位项目的冠军,在top5上的错误率为7.5%。目前为止,VGGNet依然被用来提取图像的特征。

    ​ VGGNet的优缺点

    1. 由于参数量主要集中在最后的三个FC当中,所以网络加深并不会带来参数爆炸的问题;
    2. 多个小核卷积层的感受野等同于一个大核卷积层(三个3x3等同于一个7x7)但是参数量远少于大核卷积层而且非线性操作也多于后者,使得其学习能力较强
    3. VGG由于层数多而且最后的三个全连接层参数众多,导致其占用了更多的内存(140M)
    b.ResNet

    ​ 随着深度学习的应用,各种深度学习模型随之出现,虽然在每年都会出现性能更好的新模型,但是对于前人工作的提升却不是那么明显,其中有重要问题就是深度学习网络在堆叠到一定深度的时候会出现梯度消失的现象,导致误差升高效果变差,后向传播时无法将梯度反馈到前面的网络层,使得前方的网络层的参数难以更新,训练效果变差。这个时候ResNet恰好站出来,成为深度学习发展历程中一个重要的转折点。
    ​ ResNet是由微软研究院的Kaiming He等四名华人提出,他们通过自己提出的ResNet Unit成功训练出来152层的神经网络并在ILSVRC2015比赛中斩获冠军。ResNet语义分割领域最受欢迎且最广泛运用的神经网络.ResNet的核心思想就是在网络中引入恒等映射,允许原始输入信息直接传到后面的层中,在学习过程中可以只学习上一个网络输出的残差(F(x)),因此ResNet又叫做残差网络。、

    使用到ResNet的分割模型:

    • Efficient Neural Network(ENet):该网络类似于ResNet的bottleNeck方法;
    • ResNet-38:该网络在训练or测试阶段增加并移除了一些层,是一种浅层网络,它的结构是ResNet+FCN;
    • full-resolution residual network(FRRN):FRRN网络具有和ResNet相同优越的训练特性,它由残差流和池化流两个处理流组成;
    • AdapNey:根据ResNet-50的网络进行改进,让原本的ResNet网络能够在更短的时间内学习到更多高分辨率的特征;
      ……
      ResNet的优缺点:
      1)引入了全新的网络结构(残差学习模块),形成了新的网络结构,可以使网络尽可能地加深;
      2)使得前馈/反馈传播算法能够顺利进行,结构更加简单;
      3)恒等映射地增加基本上不会降低网络的性能;
      4)建设性地解决了网络训练的越深,误差升高,梯度消失越明显的问题;
      5)由于ResNet搭建的层数众多,所以需要的训练时间也比平常网络要长。

    2.基于区域选择(regional proposal based)

    Regional proposal 在计算机视觉领域是一个非常常用的算法,尤其是在目标检测领域。其核心思想就是检测颜色空间和相似矩阵,根据这些来检测待检测的区域。然后根据检测结果可以进行分类预测。
    在语义分割领域,基于区域选择的几个算法主要是由前人的有关于目标检测的工作渐渐延伸到语义分割的领域的,接下来小编将逐步介绍其个中关系。

    Stage Ⅰ: R-CNN

    伯克利大学的Girshick教授等人共同提出了首个在目标检测方向应用的深度学习模型:Region-based Convolutional Neural Network(R-CNN)。该网络模型如下图所示,其主要流程为:先使用selective search算法提取2000个候选框,然后通过卷积网络对候选框进行串行的特征提取,再根据提取的特征使用SVM对候选框进行分类预测,最后使用回归方法对区域框进行修正。

    R-CNN的优缺点:

    • 是首个开创性地将深度神经网络应用到目标检测的算法;
    • 使用Bounding Box Regression对目标检测的框进行调整;
    • 由于进行特征提取时是串行,处理耗时过长;
    • Selective search算法在提取每一个region时需要2s的时间,浪费大量时间
    Stage Ⅱ:Fast R-CNN

    ​ 由于R-CNN的效率太低,2015年由Ross等学者提出了它的改进版本:Fast R-CNN。其网络结构图如下图所示(从提取特征开始,略掉了region的选择)Fast R-CNN在传统的R-CNN模型上有所改进的地方是它是直接使用一个神经网络对整个图像进行特征提取,就省去了串行提取特征的时间;接着使用一个RoI Pooling Layer在全图的特征图上摘取每一个RoI对应的特征,再通过FC进行分类和包围框的修正。

    Fast R-CNN的优缺点

    • 节省了串行提取特征的时间;
    • 除了selective search以外的其它所有模块都可以合在一起训练;
    • 最耗时间的selective search算法依然存在。
    Stage Ⅲ:Faster R-CNN

    2016年提出的Faster R-CNN可以说有了突破性的进展(虽然还是目标检测哈哈哈),因为它改变了它的前辈们最耗时最致命的部位:selective search算法。它将selective search算法替换成为RPN,使用RPN网络进行region的选取,将2s的时间降低到10ms,其网络结构如下图所示:

    Faster R-CNN优缺点:

    • 使用RPN替换了耗时的selective search算法,对整个网络结构有了突破性的优化;
    • Faster R-CNN中使用的RPN和selective search比起来虽然速度更快,但是精度和selective search相比稍有不及,如果更注重速度而不是精度的话完全可以只使用RPN;
    Stage Ⅳ:Mask R-CNN

    Mask R-CNN(终于到分割了!)是何恺明大神团队提出的一个基于Faster R-CNN模型的一种新型的分割模型,此论文斩获ICCV 2017的最佳论文,在Mask R-CNN的工作中,它主要完成了三件事情:目标检测,目标分类,像素级分割。
    恺明大神是在Faster R-CNN的结构基础上加上了Mask预测分支,并且改良了ROI Pooling,提出了ROI Align。其网络结构真容就如下图所示啦:

    Mask R-CNN的优缺点:

    • 引入了预测用的Mask-Head,以像素到像素的方式来预测分割掩膜,并且效果很好;
    • 用ROI Align替代了ROI Pooling,去除了RoI Pooling的粗量化,使得提取的特征与输入良好对齐;
    • 分类框与预测掩膜共享评价函数,虽然大多数时间影响不大,但是有的时候会对分割结果有所干扰。
    Stage Ⅴ:Mask Scoring R-CNN

    最后要提出的是2019年CVPR的oral,来自华中科技大学的研究生黄钊金同学提出的
    MS R-CNN,这篇文章的提出主要是对上文所说的Mask R-CNN的一点点缺点进行了修正。他的网络结构也是在Mask R-CNN的网络基础上做了一点小小的改进,添加了Mask-IoU。
    黄同学在文章中提到:恺明大神的Mask R-CNN已经很好啦!但是有个小毛病,就是评价函数只对目标检测的候选框进行打分,而不是分割模板(就是上文提到的优缺点中最后一点),所以会出现分割模板效果很差但是打分很高的情况。所以黄同学增加了对模板进行打分的MaskIoU Head,并且最终的分割结果在COCO数据集上超越了恺明大神,下面就是MS R-CNN的网络结构啦~

    MS R-CNN的优缺点:

    • 优化了Mask R-CNN中的信息传播,提高了生成预测模板的质量;
    • 未经大批量训练的情况下,就拿下了COCO 2017挑战赛实例分割任务冠军;
    • 要说缺点的话。。应该就是整个网络有些庞大,一方面需要ResNet当作主干网络,另一方面需要其它各种Head共同承担各种任务。

    3.基于RNN的图像分割

    Recurrent neural networks(RNNs)除了在手写和语音识别上表现出色外,在解决计算机视觉的任务上也表现不俗,在本篇文章中我们就将要介绍RNN在2D图像处理上的一些应用,其中也包括介绍使用到它的结构或者思想的一些模型。
    RNN是由Long-Short-Term Memory(LSTM)块组成的网络,RNN来自序列数据的长期学习的能力以及随着序列保存记忆的能力使其在许多计算机视觉的任务中游刃有余,其中也包括语义分割以及数据标注的任务。接下来的部分我们将介绍几个使用到RNN结构的用于分割的网络结构模型:

    1.ReSeg模型

    ReSeg可能不被许多人所熟知,在百度上搜索出的相关说明与解析也不多,但是这是一个很有效的语义分割方法。众所周知,FCN可谓是图像分割领域的开山作,而RegNet的作者则在自己的文章中大胆的提出了FCN的不足:没有考虑到局部或者全局的上下文依赖关系,而在语义分割中这种依赖关系是非常有用的。所以在ReSeg中作者使用RNN去检索上下文信息,以此作为分割的一部分依据。

    该结构的核心就是Recurrent Layer,它由多个RNN组合在一起,捕获输入数据的局部和全局空间结构。
    优缺点:

    • 充分考虑了上下文信息关系;
    • 使用了中值频率平衡,它通过类的中位数(在训练集上计算)和每个类的频率之间的比值来重新加权类的预测。这就增加了低频率类的分数,这是一个更有噪声的分割掩码的代价,因为被低估的类的概率被高估了,并且可能导致在输出分割掩码中错误分类的像素增加。
    2.MDRNNs(Multi-Dimensional Recurrent Neural Networks)模型

    传统的RNN在一维序列学习问题上有着很好的表现,比如演讲(speech)和在线手写识别。但是 在多为问题中应用却并不到位。MDRNNs在一定程度上将RNN拓展到多维空间领域,使之在图像处理、视频处理等领域上也能有所表现。
    该论文的基本思想是:将单个递归连接替换为多个递归连接,相应可以在一定程度上解决时间随数据样本的增加呈指数增长的问题。以下就是该论文提出的两个前向反馈和反向反馈的算法。

    4.基于上采样/反卷积的分割方法

    卷积神经网络在进行采样的时候会丢失部分细节信息,这样的目的是得到更具特征的价值。但是这个过程是不可逆的,有的时候会导致后面进行操作的时候图像的分辨率太低,出现细节丢失等问题。因此我们通过上采样在一定程度上可以不全一些丢失的信息,从而得到更加准确的分割边界。
    接下来介绍几个非常著名的分割模型:

    a.FCN(Fully Convolutional Network)

    是的!讲来讲去终于讲到这位大佬了,FCN!在图像分割领域已然成为一个业界标杆,大多数的分割方法多多少少都会利用到FCN或者其中的一部分,比如前面我们讲过的Mask R-CNN。
    在FCN当中的反卷积-升采样结构中,图片会先进性上采样(扩大像素);再进行卷积——通过学习获得权值。FCN的网络结构如下图所示:

    当然最后我们还是需要分析一下FCN,不能无脑吹啦~
    优缺点:

    • FCN对图像进行了像素级的分类,从而解决了语义级别的图像分割问题;
    • FCN可以接受任意尺寸的输入图像,可以保留下原始输入图像中的空间信息;
    • 得到的结果由于上采样的原因比较模糊和平滑,对图像中的细节不敏感;
    • 对各个像素分别进行分类,没有充分考虑像素与像素的关系,缺乏空间一致性。
    2.SetNet

    SegNet是剑桥提出的旨在解决自动驾驶或者智能机器人的图像语义分割深度网络,SegNet基于FCN,与FCN的思路十分相似,只是其编码-解码器和FCN的稍有不同,其解码器中使用去池化对特征图进行上采样,并在分各种保持高频细节的完整性;而编码器不使用全连接层,因此是拥有较少参数的轻量级网络:

    图像分割是计算机视觉研究中的一个经典难题,已经成为图像理解领域关注的一个热点,图像分割是图像分析的第一步,是计算机视觉的基础,是图像理解的重要组成部分,同时也是图像处理中最困难的问题之一。所谓图像分割是指根据灰度、彩色、空间纹理、几何形状等特征把图像划分成若干个互不相交的区域,使得这些特征在同一区域内表现出一致性或相似性,而在不同区域间表现出明显的不同。简单的说就是在一副图像中,把目标从背景中分离出来。对于灰度图像来说,区域内部的像素一般具有灰度相似性,而在区域的边界上一般具有灰度不连续性。 关于图像分割技术,由于问题本身的重要性和困难性,从20世纪70年代起图像分割问题就吸引了很多研究人员为之付出了巨大的努力。虽然到目前为止,还不存在一个通用的完美的图像分割的方法,但是对于图像分割的一般性规律则基本上已经达成的共识,已经产生了相当多的研究成果和方法。

    本文对于目前正在使用的各种图像分割方法进行了一定的归纳总结,由于笔者对于图像分割的了解也是初窥门径,所以难免会有一些错误,还望各位读者多多指正,共同学习进步。

    SetNet的优缺点:

    • 保存了高频部分的完整性;
    • 网络不笨重,参数少,较为轻便;
    • 对于分类的边界位置置信度较低;
    • 对于难以分辨的类别,例如人与自行车,两者如果有相互重叠,不确定性会增加。
      以上两种网络结构就是基于反卷积/上采样的分割方法,当然其中最最最重要的就是FCN了,哪怕是后面大名鼎鼎的SegNet也是基于FCN架构的,而且FCN可谓是语义分割领域中开创级别的网络结构,所以虽然这个部分虽然只有两个网络结构,但是这两位可都是重量级嘉宾,希望各位能够深刻理解~

    5.基于提高特征分辨率的分割方法

    在这一个模块中我们主要给大家介绍一下基于提升特征分辨率的图像分割的方法。换一种说法其实可以说是恢复在深度卷积神经网络中下降的分辨率,从而获取更多的上下文信息。这一系列我将给大家介绍的是Google提出的DeepLab 。
    DeepLab是结合了深度卷积神经网络和概率图模型的方法,应用在语义分割的任务上,目的是做逐像素分类,其先进性体现在DenseCRFs(概率图模型)和DCNN的结合。是将每个像素视为CRF节点,利用远程依赖关系并使用CRF推理直接优化DCNN的损失函数。
    在图像分割领域,FCN的一个众所周知的操作就是平滑以后再填充,就是先进行卷积再进行pooling,这样在降低图像尺寸的同时增大感受野,但是在先减小图片尺寸(卷积)再增大尺寸(上采样)的过程中一定有一些信息损失掉了,所以这里就有可以提高的空间。
    接下来我要介绍的是DeepLab网络的一大亮点:Dilated/Atrous Convolution,它使用的采样方式是带有空洞的采样。在VGG16中使用不同采样率的空洞卷积,可以明确控制网络的感受野。

    图a对应3x3的1-dilated conv,它和普通的卷积操作是相同的;图b对应3x3的2-dilated conv,事迹卷积核的尺寸还是3x3(红点),但是空洞为1,其感受野能够达到7x7;图c对应3x3的4-dilated conv,其感受野已经达到了15x15.写到这里相信大家已经明白,在使用空洞卷积的情况下,加大了感受野,使每个卷积输出都包含了较大范围的信息。
    这样就解决了DCNN的几个关于分辨率的问题:
    1)内部数据结构丢失;空间曾计划信息丢失;
    2)小物体信息无法重建;
    当然空洞卷积也存在一定的问题,它的问题主要体现在以下两方面:
    1)网格效应
    加入我们仅仅多次叠加dilation rate 2的 3x3 的卷积核则会出现以下问题

    我们发现卷积核并不连续,也就是说并不是所有的像素都用来计算了,这样会丧失信息的连续性;
    2)小物体信息处理不当
    我们从空洞卷积的设计背景来看可以推测出它是设计来获取long-ranged information。然而空洞步频选取得大获取只有利于大物体得分割,而对于小物体的分割可能并没有好处。所以如何处理好不同大小物体之间的关系也是设计好空洞卷积网络的关键。

    6.基于特征增强的分割方法

    基于特征增强的分割方法包括:提取多尺度特征或者从一系列嵌套的区域中提取特征。在图像分割的深度网络中,CNN经常应用在图像的小方块上,通常称为以每个像素为中心的固定大小的卷积核,通过观察其周围的小区域来标记每个像素的分类。在图像分割领域,能够覆盖到更大部分的上下文信息的深度网络通常在分割的结果上更加出色,当然这也伴随着更高的计算代价。多尺度特征提取的方法就由此引进。
    在这一模块中我先给大家介绍一个叫做SLIC,全称为simple linear iterative cluster的生成超像素的算法。
    首先我们要明确一个概念:啥是超像素?其实这个比较容易理解,就像上面说的“小方块”一样,我们平常处理图像的最小单位就是像素了,这就是像素级(pixel-level);而把像素级的图像划分成为区域级(district-level)的图像,把区域当成是最基本的处理单元,这就是超像素啦。
    算法大致思想是这样的,将图像从RGB颜色空间转换到CIE-Lab颜色空间,对应每个像素的(L,a,b)颜色值和(x,y)坐标组成一个5维向量V[l, a, b, x, y],两个像素的相似性即可由它们的向量距离来度量,距离越大,相似性越小。
    算法首先生成K个种子点,然后在每个种子点的周围空间里搜索距离该种子点最近的若干像素,将他们归为与该种子点一类,直到所有像素点都归类完毕。然后计算这K个超像素里所有像素点的平均向量值,重新得到K个聚类中心,然后再以这K个中心去搜索其周围与其最为相似的若干像素,所有像素都归类完后重新得到K个超像素,更新聚类中心,再次迭代,如此反复直到收敛。
    有点像聚类的K-Means算法,最终会得到K个超像素。
    Mostahabi等人提出的一种前向传播的分类方法叫做Zoom-Out就使用了SLIC的算法,它从多个不同的级别提取特征:局部级别:超像素本身;远距离级别:能够包好整个目标的区域;全局级别:整个场景。这样综合考虑多尺度的特征对于像素或者超像素的分类以及分割来说都是很有意义的。
    接下来的部分我将给大家介绍另一种完整的分割网络:PSPNet:Pyramid Scene Parsing Network
    论文提出在场景分割是,大多数的模型会使用FCN的架构,但是FCN在场景之间的关系和全局信息的处理能力存在问题,其典型问题有:1.上下文推断能力不强;2.标签之间的关系处理不好;3.模型可能会忽略小的东西。
    本文提出了一个具有层次全局优先级,包含不同子区域时间的不同尺度的信息,称之为金字塔池化模块。
    该模块融合了4种不同金字塔尺度的特征,第一行红色是最粗糙的特征–全局池化生成单个bin输出,后面三行是不同尺度的池化特征。为了保证全局特征的权重,如果金字塔共有N个级别,则在每个级别后使用1×1 1×11×1的卷积将对于级别通道降为原本的1/N。再通过双线性插值获得未池化前的大小,最终concat到一起。其结构如下图:

    最终结果就是,在融合不同尺度的feature后,达到了语义和细节的融合,模型的性能表现提升很大,作者在很多数据集上都做过训练,最终结果是在MS-COCO数据集上预训练过的效果最好。

    为了捕捉多尺度特征,高层特征包含了更多的语义和更少的位置信息。结合多分辨率图像和多尺度特征描述符的优点,在不丢失分辨率的情况下提取图像中的全局和局部信息,这样就能在一定程度上提升网络的性能。

    7.使用CRF/MRF的方法

    首先让我们熟悉熟悉到底啥是MRF的CRF的。
    MRF全称是Marcov Random Field,马尔可夫随机场,其实说起来笔者在刚读硕士的时候有一次就有同学在汇报中提到了隐马尔可夫、马尔可夫链啥的,当时还啥都不懂,小白一枚(现在是准小白hiahia),觉得马尔可夫这个名字贼帅,后来才慢慢了解什么马尔科夫链呀,马尔可夫随机场,并且在接触到图像分割了以后就对马尔科夫随机场有了更多的了解。
    MRF其实是一种基于统计的图像分割算法,马尔可夫模型是指一组事件的集合,在这个集合中,事件逐个发生,并且下一刻事件的发生只由当前发生的事件决定,而与再之前的状态没有关系。而马尔可夫随机场,就是具有马尔可夫模型特性的随机场,就是场中任何区域都只与其临近区域相关,与其他地方的区域无关,那么这些区域里元素(图像中可以是像素)的集合就是一个马尔可夫随机场。
    CRF的全称是Conditional Random Field,条件随机场其实是一种特殊的马尔可夫随机场,只不过是它是一种给定了一组输入随机变量X的条件下另一组输出随机变量Y的马尔可夫随机场,它的特点是埃及设输出随机变量构成马尔可夫随机场,可以看作是最大熵马尔可夫模型在标注问题上的推广。
    在图像分割领域,运用CRF比较出名的一个模型就是全连接条件随机场(DenseCRF),接下来我们将花费一些篇幅来简单介绍一下。
    CRF在运行中会有一个问题就是它只对相邻节点进行操作,这样会损失一些上下文信息,而全连接条件随机场是对所有节点进行操作,这样就能获取尽可能多的临近点信息,从而获得更加精准的分割结果。
    在Fully connected CRF中,吉布斯能量可以写作:

    我们重点关注二元部分:

    其中k(m)为高斯核,写作:

    该模型的一元势能包含了图像的形状,纹理,颜色和位置,二元势能使用了对比度敏感的的双核势能,CRF的二元势函数一般是描述像素点与像素点之间的关系,鼓励相似像素分配相同的标签,而相差较大的像素分配不同标签,而这个“距离”的定义与颜色值和实际相对距离有关,这样CRF能够使图像尽量在边界处分割。全连接CRF模型的不同就在于其二元势函数描述的是每一个像素与其他所有像素的关系,使用该模型在图像中的所有像素对上建立点对势能从而实现极大地细化和分割。
    在分割结果上我们可以看看如下的结果图:

    可以看到它在精细边缘的分割比平常的分割方法要出色得多,而且文章中使用了另一种优化算法,使得本来需要及其大量运算的全连接条件随机场也能在很短的时间里给出不错的分割结果。
    至于其优缺点,我觉得可以总结为以下几方面:

    • 在精细部位的分割非常优秀;
    • 充分考虑了像素点或者图片区域之间的上下文关系;
    • 在粗略的分割中可能会消耗不必要的算力;
    • 可以用来恢复细致的局部结构,但是相应的需要较高的代价。
      OK,那么本次的推送就到这里结束啦,本文的主要内容是对图像分割的算法进行一个简单的分类和介绍。综述对于各位想要深入研究的看官是非常非常重要的资源:大佬们经常看综述一方面可以了解算法的不足并在此基础上做出改进;萌新们可以通过阅读一篇好的综述入门某一个学科,比如今天的内容就是图像分割。
      谢谢各位朋友们的观看!

    推荐阅读

    如何从零开始系统化学习视觉SLAM?
    从零开始一起学习SLAM | 为什么要学SLAM?
    从零开始一起学习SLAM | 学习SLAM到底需要学什么?
    从零开始一起学习SLAM | SLAM有什么用?
    从零开始一起学习SLAM | C++新特性要不要学?
    从零开始一起学习SLAM | 为什么要用齐次坐标?
    从零开始一起学习SLAM | 三维空间刚体的旋转
    从零开始一起学习SLAM | 为啥需要李群与李代数?
    从零开始一起学习SLAM | 相机成像模型
    从零开始一起学习SLAM | 不推公式,如何真正理解对极约束?
    从零开始一起学习SLAM | 神奇的单应矩阵
    从零开始一起学习SLAM | 你好,点云
    从零开始一起学习SLAM | 给点云加个滤网
    从零开始一起学习SLAM | 点云平滑法线估计
    从零开始一起学习SLAM | 点云到网格的进化
    从零开始一起学习SLAM | 理解图优化,一步步带你看懂g2o代码
    从零开始一起学习SLAM | 掌握g2o顶点编程套路
    从零开始一起学习SLAM | 掌握g2o边的代码套路
    零基础小白,如何入门计算机视觉?
    SLAM领域牛人、牛实验室、牛研究成果梳理
    我用MATLAB撸了一个2D LiDAR SLAM
    可视化理解四元数,愿你不再掉头发
    最近一年语义SLAM有哪些代表性工作?
    视觉SLAM技术综述
    汇总 | VIO、激光SLAM相关论文分类集锦
    研究SLAM,对编程的要求有多高?
    2018年SLAM、三维视觉方向求职经验分享
    2018年SLAM、三维视觉方向求职经验分享
    深度学习遇到SLAM | 如何评价基于深度学习的DeepVO,VINet,VidLoc?
    视觉SLAM关键方法总结
    SLAM方向公众号、知乎、博客上有哪些大V可以关注?
    SLAM实验室
    SLAM方向国内有哪些优秀公司?
    SLAM面试常见问题
    SLAM相关领域数据集调研
    从零开始一起学习SALM-ICP原理及应用
    解放双手——相机与IMU外参的在线标定
    目标检测

    展开全文
  • 标准分地图-选择比例尺

    千次阅读 2016-09-13 11:51:10
    BIGEMAP地图下载器提供了多种选择的下载方式,方便用户得到不同的应用当中: 1、矩形框选择区域下载 2、多边形选择区域下载 3、根据行政区(省市县区)域边界选择下载 4、导入外部边界文件下载(支持kml/kmz/shp...

    标准分幅下载

    BIGEMAP地图下载器提供了多种选择的下载方式,方便用户得到不同的应用当中:

    1、矩形框选择区域下载

    2、多边形选择区域下载

    3、根据行政区(省市县区)域边界选择下载

    4、导入外部边界文件下载(支持kml/kmz/shp格式)

    5、标准分幅下载

    6、指定矩形框经纬度范围下载

          标准分幅下载的主要目的:当我们的下载超过2G内容的时候,我们就建议用户选择标准分幅下载,标准分幅下载的图幅,易于后期使用、管理,保存,是全世界通用的一种分幅下载方式,我们的测绘、国土流通的地形图都是采用分幅下载、保存和使用的,同时分幅下载也死可以实现自动拼接成一整幅。

    标准分幅的比例尺:

    ff1.png

            此处的比例尺,不是影像下载的精度比例尺,而是代表每一幅图所包含区域的面积大小。假设1:5000 表示每一幅是10平方公里,则1:10000每一幅所包含的面积为100平方公里。【实际并不是这么大面积,此处只是举例】,在选定比例尺之后,无论你下载的级别是多少,都代表你下载的是形同面积的范围。

    第一步:选择分幅比例尺

            一般情况下,我们选择1:10000的分幅比例尺,如下图:

    ff2.png

    第二步骤:按照标准分幅下载

            1、可以选择单幅下载

            2、可以选择多幅下载

            3、可以导出分幅框

            4、分幅后可自动拼接成一整幅、也可以任意拼接其中的某几幅

     2.1 选择单幅下载

               拖动整个屏幕,或者在标准分幅的下拉列表中输入你要找的图幅号,找到你要下载的某一幅;然后鼠标指到那一图幅【双击左键】,如下图:

    ff3.png

            根具提示:再次【双击左键】,弹出下载对话框。

            如果选择的图幅不是你要下载的,可以【单击右键】,取消下载,同时回到标准分幅的开始状态。

     

      2.2 选择多幅下载 

            在选择标准分幅比例尺之后,在软件的最上面工具栏选择【】或者【多边形】,单机左键选择 。 

            用矩形框或者多边形框来选在你要下载的图幅的范围,如下图所示:

    ff4.png

            根具提示:再次【双击左键】,弹出下载对话框。

            如果选择的图幅不是你要下载的,可以【单击右键】,取消下载,同时回到标准分幅的开始状态。

     

      2.3 导出分幅框

           选择下图中红色箭头④所指向的位置,然后保存。

     ff6.png

      2.4 拼接下载的图幅

           打开下载完成的文件夹,可以看到我下载了多幅分幅图,并且每一幅的名称对应的就是该幅的分幅号,如下图:

    ff7.png  

           下载安装【global mapper】GIS工具软件。(本网站的软件下载,其他软件里面有提供下载),打开global mapper(启动中文版,在安装目录下有个一图标是中文启动),如下图所示:

    ff8.png

           将下载的后缀名为【tff】的文件拖到打开的global mapper软件里,可以拖入一幅,也可以拖入多幅,软件会自动无缝拼接,如下图所示:

    ff9.png

            从上图我们看出,下载后的和下载前选择的 图幅范围是一模一样的,实现了自动拼接功能。

            同时,在下载的文件夹里面还有个后缀名为【KML】的文件,这个是分幅的【分幅框】也一并下载下来了,我们一并拖入到global mapper里面看一看,如下图:

    ff11.png

      然后选择工具栏的【数字化工具】,如下图:

    ff12.png

     拖动这个工具框选所有的图幅,如下图:

    ff14.png

     

           框住后,鼠标点右键,选择上图红色箭头所指,弹出如下对话框:

    ff15.png

         选择上图红色的单选按钮,然后确定,在空白处双击鼠标,如下图所示:

    f16.png

     

    展开全文
  • 很久之前从网上看到了QQ同时在线人数的flash地图,就想在超图桌面产品中制作一幅类似静态效果的地图,但一直苦于没有合适的数据来展现。皇天不负有心人,前不久从同事那里获得到一份北京各个地点微博登录人数的数据...

    很久之前从网上看到了QQ同时在线人数的flash地图,就想在超图桌面产品中制作一幅类似静态效果的地图,但一直苦于没有合适的数据来展现。皇天不负有心人,前不久从同事那里获得到一份北京各个地点微博登录人数的数据,貌似可以用来制作类似“星光闪闪”的地图,今天花了点时间小试了一把,成图效果如下:
    这里写图片描述
    图1 地图效果示意

    效果貌似还不错,那接下来就把这幅地图的制作过程分享一下,希望能对有此制图需求的读者有所帮助。

    使用超图桌面产品版本:SuperMap iDesktop 8C。

    使用数据:点数据集:BJ_CHECKINS_SINA_WEIBO(北京微博登录数据),

    面数据集:County_R(北京行政区划面)

    步骤一:地图背景的设置。

    QQ同时在线人数地图(后面简称QQ在线地图),使用的是夜视模式,在这里,我们也采用同样的夜视效果。如图2所示,有两个需要设置颜色风格的地方:

    ①County_R北京行政区划面的填充风格设置;

    ②地图背景颜色的设置。

    这里写图片描述

    图2 要设置颜色风格的区域示意

    这两个颜色直接选取QQ在线地图上的色彩就可以。iDesktop
    8C和QQ在线地图同时打开在屏幕上,使用iDesktop
    色板中提供的取色器,直接拾取颜色。如图3所示。

    这里写图片描述
    为了能看出北京的行政区划界线,可以将面区域边线的颜色设置的稍浅一些。线型还是采用实线填充。

    步骤二:专题图制作

    所有的微博登陆记录,都存储在点数据集BJ_CHECKINS_SINA_WEIBO的checkin字段中,Checkin中的数值从1到几千不等,为了表现其整体分布情况,我们采用范围分段专题图,不同的段值区间使用不同的颜色来区分。

    将BJ_CHECKINS_SINA_WEIBO数据集添加到当前地图窗口,并对其制作范围分段专题图。范围分段专题图的具体参数值设置,如图4所示。

    这里写图片描述

    图4 范围分段专题图参数示意

    解释几个参数的设置:

    1. 分段方法采用“自定义分段”的方式,是根据checkin字段中字段值的特点(几个到上千不等),分为14段,手动调整了每个段值区间。

    2. 颜色方案选择了系统默认提供的蓝白的渐变,颜色越浅趋于白色,说明当前地点微博登陆的人数越多。

    3. 为了有透视感的效果,对每个分段的颜色风格都做了不同程度的透明度设置。例如最后一个段值2000<=X<=max,它的颜色值中,设置了Alpha的数值。

    这里写图片描述

    图5 设置颜色的Alpha值

    注意:8C桌面中,要设置颜色值中的Alpha数值,需要先开启地图属性中的“Alpha通道”。

    1. 点数据量较大,为了保证地图的浏览效率,采用了默认点符号,符号大小也是默认数值。自己在制图过程中,可以设置为符合数据需要的符号和大小。

    步骤三:其他相关设置

    1. 设置对象显示顺序

    因为点数据量较大,在地图缩小时,登陆数值较高的记录有可能会被其他数值小的点所压盖,如图6所示。

    这里写图片描述
    图6 默认地图效果

    SuperMap中的显示原则是:按照绘制的顺序显示,当对象有叠加的时候,先看到的是最后绘制的对象,也即SMID最大的那个对象。默认的对象显示顺序,是按照SMID的升序显示的。

    那如果存在如图6所示的问题,该如何解决呢?

    设置“图层属性“中的“对象显示顺序字段”即可。默认也是按照升序的方式,可以根据需要设置为降序。本示例中,设置对象显示顺序字段为”checkin“之后,地图效果就如图7所示。

    这里写图片描述
    这里写图片描述

    图 7 调整对象显示顺序后的地图效果

    1. 开启线型反走样

    虽然我们在范围分段专题图中设置的为点符号的风格,没有涉及到线,但当给定的符号大小够大时,在地图上符号显示时符号的边缘仍旧会有锯齿状存在,如图8所示。

    这里写图片描述

    图8 未开启线型反走样

    此时,建议开启”地图属性“中的”线型反走样“,锯齿能得到明显的改善,如图9所示。

    这里写图片描述

    图 9 开启线型反走样设置

    至此,“星光闪闪“的地图制作完成了,效果即如1所示。当然,我们还可以为地图手动添加上名称、图例等,让信息表达的更明确,如图10所示。

    这里写图片描述

    图 10 最终效果图

    展开全文
  • 一幅图弄清DFT与DTFT,DFS的关系

    千次阅读 2015-09-25 19:47:51
    这点对照DFS和DFT的定义式也可以轻易的看出。因此DFS与DFT的本质是一样的,只不过描述的方法不同而已。  不知道经过上面的解释,您是否明白各种T的关系了呢?如果您不是算法设计者,其实只要懂得如何使用FFT...
  • 【技术综述】文道尽传统图像降噪方法

    万次阅读 多人点赞 2019-01-08 14:54:01
    【技术综述】文道尽传统图像降噪方法 图像预处理算法的好坏直接关系到后续图像处理的效果,如图像分割、目标识别、边缘提取等,为了获取高质量的数字图像,很多时候都需要对图像进行降噪处理,尽可能的保持原始...
  • 一幅图像可以被定义为一个二维函数f(x,y),其中(x,y)是空间(平面)坐标,在任何坐标(x,y)处的幅度f被定义为图像在这一位置的亮度。 图像在x和y坐标以及在幅度变化上是连续的。要将这样的一幅图像转换成数字形式,...
  • 本文通过理论和实验简单说明图像直方均衡化次数不同,均衡化结果和灰度直方都相同。
  • 一幅图弄清DFT与DTFT,FFT的关系

    万次阅读 多人点赞 2017-02-16 18:53:45
    (在任何本信号与系统课本里,此两条性质有详细公式证明) 下面,就用这两条性质来说明DFT,DTFT,DFS,FFT之间的联系: 先看图片: 首先来说(1)和(2),对于个模拟信号,如(1)所示,要分析它的频率成分...
  • 图像拼接(七):OpenCV单应变换模型拼接多图像

    万次阅读 热门讨论 2017-03-06 10:50:05
    求取每相邻两幅图像的单应矩阵拼接多图像,需要计算每相邻两幅图像的单应矩阵,上篇已经封装了求取单应矩阵的类,可以拿来用。 现有4图像:img1img1,img2img2,img3img3,img4img4。依次从右向左排列,拼接...
  • 图片马赛克检测

    千次阅读 2015-11-09 11:55:02
    视频在传输过程中,由于编解码...以一幅图片为例,来说明马赛克检测所用方法,这里采用的图片如下所示: 可以发现,图片中人物脸部打了马赛克。针对这片区域的马赛克,看本算法是否能够有效识别。首先,对上进行Ca
  • 灰度图像增强和图像去噪

    万次阅读 2016-01-17 21:11:04
    、  前言... 2 二、  灰度变换增强的方法及其实现... 2 1.  线性灰度变换... 2 2.  分段线性灰度变换... 4 3.  对数函数灰度变换... 6 4.  反对数函数灰度变换... 8 5.  伽马变换... 9
  • 基于LABVIEW机器视觉-直方均衡化

    千次阅读 2019-05-24 23:47:57
    基于LABVIEW机器视觉-直方均衡化 最近学习了一些关于机器视觉的内容,感觉labview机器视觉还挺容易上手,入门挺简单的。当然要学会种编程语言是需要很长时间的。不管你是利用halcon、opencv还是labview中的视觉...
  • 利用python-docx批量处理Word文件—图片

    万次阅读 多人点赞 2018-10-30 13:35:34
    图片是Word的种特殊内容,这篇文章主要内容是如何利用python-docx批量提取Word中的图片,以及如何在Word国插入图片
  • 图片特征

    千次阅读 2017-04-07 20:59:10
    常用的图像特征有颜色特征、纹理特征、形状特征、空间关系特征。  颜色特征 ()特点:颜色特征是种全局特征,描述了图像或图像区域所对应的景物的表面性质。一般颜色特征是基于像素...颜色直方 其优点在于
  •  前面一节介绍了可以通过标记序号分割原获得小拼图块数据矩阵的方法,一幅拼图可由9块小拼图块拼接而成,因此用一个9个元素的标记矩阵,每个位置上的元素值作为一个标记序号表示相应位置的拼图块,就可以通过这个...
  • 解读灰度直方的信息

    千次阅读 2018-03-16 21:52:24
    任何一幅图像都有灰度直方,但相同的灰度直方可能对应不同的图像,因为在形成灰度直方的时候丢失了空间信息,即你并不能知道该灰度对应于图像中的位置。 图像获取质量评价 观察上面的...
  • 直方均衡是利用一幅图像的直方特性来自动改善图像质量的一种方式,通过变换函数,将一些出现频数较低的灰度级归并,使得处理后的各灰度级频数差距减小,从而得到一个比较均匀的直方。经过直方均衡,一幅图像...
  • 别再说,不懂什么是数据了

    千次阅读 2020-06-11 11:13:14
    在众多不同的数据模型里,关系数据模型自20世纪80年代就处于统治地位,而且出现了不少巨头,如Oracle、MySQL和MSSQL,它们也被称为关系数据库管理系统(RDBMS)。然而,随着关系数据库使用范围的不断扩大,也暴露出...
  • 本次涉及了对原图像增加高斯噪声、多次叠加原和高斯噪声以及叠加后的平均图像。 close all; %关闭当前所有图形窗口,清空工作空间变量,清除工作空间所有变量 clear all; clc; RGB=imread('eight.tif'); %读入...
  • 基于颜色特征的图像检索(

    万次阅读 热门讨论 2019-01-12 15:46:22
    目的:实现“以搜图”的功能,给定一张测试图像,在训练集中找出最接近的10张图像(实际上是检索类别相同的图像) 基本思路:对训练集中的已有图像进行特征提取,对所提取的特征建立索引;在检索时,对测试图像...
  • 课程笔记4--图像K空间理解

    万次阅读 2017-01-04 18:25:30
    事实上,K空间中的数据正是图像空间中的数据作二维傅立叶变换的结果(1),也就是说,我们的“大脑图像”可以被看作是由系列频率、相位、方向各异的二维正弦波叠加而成的,而K空间的数据正表示了图像的正弦波...
  • 背景:续上篇,继续介绍如何将多JPG图像数据存入DCM文件。即将有损压缩数据直接写入DCM文件,存储为Multi-frame形式。
  • 通常而言,编程和绘画可谓风马牛不相及。 本文却通过对比一幅简笔画过程和一段代码,将绘画和程序联系起来,并且介绍了编程的一些基本概念。
  • 图像的表示方法和种类

    千次阅读 2019-02-17 18:21:29
    我们可以通过这样理解数字图像,首先图像是由许多像素组成的,所以说图像处理是在二维平面上对图片的每个像素进行处理,而如何知道我们处理的是这个像素,而不是另外个像素,如何定义个图像的最基本的元素。...
  • CSS3 图像边框 border-image属性

    千次阅读 2018-02-16 22:13:33
    该属性的优点是,可以根据一些简单的规则,把一幅图像划分为 9 个单独的部分,浏览器会自动使用合适的部分作为边框的对应部分。需要注意的是,只有当 border-style属性取值为 none 时,border-image属性才会有效。...
  • 图像检索文献总结()

    万次阅读 2018-01-31 14:30:39
    图像检索新人 总结目前图像检索现状 方便自己与他人查看 资料收集自网络 如有侵权 请联系删除   端到端的特征学习方法 NetVLAD: CNN architecture for weakly ...该文章关注实例搜索的个具体应用——位...
  • 图像理解之图像分割 image segmentation

    千次阅读 2019-03-28 10:01:00
    本方法的关键想法便是,保证下可以从输入中学到与已经学到的信息不同的新东西(因为下层同时得到了前层的输出以及原始的输入)。另外,这种连接也协助解决了梯度消失的问题。   5 ResNet中的残差...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 53,723
精华内容 21,489
关键字:

一幅图可以看出不同图