Opencv学习笔记(总结)

1、加载图片

    //__________加载图片______________
    // 注意imread的第二个参数intflag默认是1,即原色彩,但是他可以指定多种色彩,比如0即灰色,一个彩色的图载入进去就会变成灰色
    // CV_LOAD_IMAGE_UNCHANGED = -1,// 此值已被废弃
    // CV_LOAD_IMAGE_GRAYSCALE = 0,// 灰度(灰色、黑白)
    // CV_LOAD_IMAGE_COLOR = 1,// 彩色
    // CV_LOAD_IMAGE_ANYDEPTH,// 深度返回?
    // 一个彩色可以变成灰色,一个灰色却不能变为彩色

    Mat srcImage = imread("1_5_12.jpg",0);// 图片文件放在debug/release文件夹同级
    namedWindow("【原始图】");
    imshow("【原始图】",srcImage);
    waitKey(0);

2、图像腐蚀

    //_________图像腐蚀_______________

    Mat srcImage = imread("1_5_2.jpg");// 加载图片

    namedWindow("【原图】腐蚀操作");// 窗口

    imshow("【原图】腐蚀操作",srcImage);// 显示原图

    Mat element = getStructuringElement(MORPH_RECT,Size(15,15));// 进行腐蚀操作

    Mat dstImage;

    erode(srcImage,dstImage,element);

    namedWindow("【效果图】腐蚀操作");

    imshow("【效果图】腐蚀操作",dstImage);// 显示效果图

    waitKey(0);

3、图像模糊

    //______________图像模糊____________
    Mat srcImage = imread("1_5_3.jpg");

    namedWindow("均值滤波【原图】");

    imshow("均值滤波【原图】",srcImage);

    Mat dstImage;

    blur(srcImage,dstImage,Size(7,7));

    namedWindow("均值滤波【效果图】");

    imshow("均值滤波【效果图】",dstImage);

    waitKey(0);

4、边缘检测

    //_____________边缘检测____________
    Mat srcImage = imread("1_5_4.jpg");

    namedWindow("【原始图】Canny边缘检测");

    imshow("【原始图】Canny边缘检测",srcImage);

    Mat dstImage,edge,grayImage;

    dstImage.create(srcImage.size(),srcImage.type());// 创建和src同样类型和大小的矩阵

    cvtColor(srcImage,grayImage,CV_BGR2GRAY);// opencv3:COLOR_BGR2GRAY;opencv2:CV_BGR2GRAY

    blur(grayImage,edge,Size(3,3));// 先使用3*3内核来降噪

    Canny(edge,edge,3,9,3);// 运行Canny算子

    namedWindow("【效果图】Canny边缘检测");

    imshow("【效果图】Canny边缘检测",edge);

    waitKey(0);

5、读取视频

    //_____________读取视频___________________
    VideoCapture capture("1_6_1.avi");// 读取视频

    namedWindow("读取视频");

    while(1)
    {
        Mat frame;

        capture>>frame;// 读取当前帧

        imshow("读取视频",frame);// 显示当前帧

        waitKey(30);
    }

6、调用摄像头

    //______________调用摄像头_____________
    VideoCapture capture(0);

    namedWindow("读取视频");

    while(1)
    {
        Mat frame;

        capture>>frame;

        imshow("读取视频",frame);

        waitKey(30);
    }

7、摄像头边缘检测

    //______________摄像头边缘检测_____________
    VideoCapture capture(0);

    Mat edges;

    namedWindow("被canny后的视频");

    while(1)
    {
        Mat frame;

        capture>>frame;

        cvtColor(frame,edges,COLOR_BGR2GRAY);

        blur(edges,edges,Size(7,7));

        Canny(edges,edges,0,30,3);

        imshow("被canny后的视频",edges);

        waitKey(30);
    }

8、用imwrite输出png

    //_____________用imwrite输出png___________________

    Mat mat(480,640,CV_8UC4);// 创建带alpha通道的Mat

    createAlphaMat(mat);

    vector compression_params;

    compression_params.push_back(IMWRITE_PNG_COMPRESSION);

    compression_params.push_back(9);

    try
    {
        namedWindow("透明Alpha值图");

        imwrite("透明Alpha值图",mat,compression_params);// imwrite测试失败,不知原因

        namedWindow("生成的PNG图");

        imshow("生成的PNG图",mat);

        fprintf(stdout,"PNG图片文件的alpha数据保存完毕~\n可以在工程目录下查看由imwrite函数生成的图片\n");

        waitKey(0);
    }
    catch(runtime_error & ex)
    {
        fprintf(stderr,"图像转换成PNG格式发生错误:%s\n",ex.what());

        return 1;
    }
void createAlphaMat(Mat & mat)
{
    for(int i = 0;i(i,j);

            rgba[0] = UCHAR_MAX;

            rgba[1] = saturate_cast((float(mat.cols-j))/((float)mat.rows)*UCHAR_MAX);

            rgba[2] = saturate_cast((float(mat.rows-i))/((float)mat.rows)*UCHAR_MAX);

            rgba[3] = saturate_cast(0.5*(rgba[1]+rgba[2]));
        }
    }
}

9、综合示例:图像载入、显示和混合

#include "study3_1_9.h"
#include 
#include 
#include 
#include 
#include 

#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace cv;
using namespace std;

Study3_1_9::Study3_1_9()
{
    //___________载入和显示____________
    Mat girl = imread("girl.jpg");

    namedWindow("【1】动漫图");

    imshow("【1】动漫图",girl);

    //___________初级图像混合__________
    Mat image = imread("dota.jpg");

    Mat logo = imread("dota_logo.jpg");

    qDebug()<<"image-cols:"<


<1>指定ROI(感兴趣区域)

Mat image("xxx.jpg");
Mat imageROI = image(Rect(x,y,width,height));//在image内指定一个矩形,指定矩形的起点以及宽和高

Mat imageROI = image(Range(x1,xn),Range(y1,yn));// 或者指定一个x坐标的起止点(序列),指定一个y坐标的起止点(序列)

// 需要注意的是,不管是哪种方法,范围内所有点必须在image范围之内

<2>图片融合

    // 资源1,alpha,资源2,alpha,偏差,输出
    addWeighted(imageROI,0.1,logo,0.1,0,imageROI);// 图片融合,就是刚才切出来的图和要贴上去的图做一个融合

    // 注意修改了imageROI其实也修改了image

10、用createTrackbar创建滑动条

注意:载入的两个图片必须一样大小。

下面的示例来自于:http://monkeycoding.com/?p=652,感谢!

#include 
#include 
using namespace cv;

int sliderValue;
Mat src1, src2;

void on_trackbar(int, void*){
    double alpha = (double) sliderValue/100.0 ;
    double beta = ( 1.0 - alpha );
    Mat dst;

    addWeighted( src1, alpha, src2, beta, 0.0, dst);
    imshow("trackbar demo", dst);
}

int main(){
    src1 = imread("beach.jpg",CV_LOAD_IMAGE_UNCHANGED);
    src2 = imread("cat.jpg",CV_LOAD_IMAGE_UNCHANGED);
    sliderValue = 0;
    int sliderMaxValue = 100;

    namedWindow("trackbar demo", 0);
    createTrackbar("Ratio", "trackbar demo", &sliderValue, sliderMaxValue, on_trackbar);
    on_trackbar(sliderValue, 0 );

    waitKey(0);
    return 0;
}

11、鼠标交互setMouseCallback

注意:窗口不要用宏定义+中文,不知道为什么就是出问题,改了就好了

#include 
#include 

using namespace cv;

// 全局函数声明
void on_MouseHandle(int event,int x,int y,int flags,void * param);
void DrawRectangle(cv::Mat& img,cv::Rect box);
void ShowHelpText();

// 全局变量声明
Rect g_rectangle;
bool g_bDrawingBox = false;
RNG g_rng(123456);


int main(int argc,char ** argv)
{
    // 鼠标交互setMouseCallback

    // 准备参数
    g_rectangle = Rect(-1,-1,0,0);
    Mat srcImage(600,800,CV_8UC3),tempImage;
    srcImage.copyTo(tempImage);

    g_rectangle = Rect(-1,-1,0,0);
    srcImage = Scalar::all(0);

    // 设置鼠标操作回调
    namedWindow("testw");
    setMouseCallback("testw",on_MouseHandle,(void*)&srcImage);

    // 程序主循环,当进行绘制的标识符为真时,进行绘制
    while(1)
    {
        srcImage.copyTo(tempImage);// 复制源图到临时变量
        if(g_bDrawingBox)
            DrawRectangle(tempImage,g_rectangle);// 当进行绘制的标识符为真时,则进行绘制
        imshow("testw",tempImage);
        if(waitKey(10)==27)
            break;// 当按下esc,退出
    }
    return 0;

}

void on_MouseHandle(int event, int x, int y, int flags, void *param)
{
    Mat & image = *(cv::Mat*) param;// 一个Mat类型的指针执行指针标识,就变成引用

    switch(event)
    {
        case EVENT_MOUSEMOVE:
        {
            if(g_bDrawingBox)
            {
                g_rectangle.width = x-g_rectangle.x;
                g_rectangle.height = y-g_rectangle.y;
            }
        }
            break;
        case  EVENT_LBUTTONDOWN:
        {
            g_bDrawingBox = true;
            g_rectangle = Rect(x,y,0,0);// 记录起始点
        }
            break;
        case EVENT_LBUTTONUP:
        {
            g_bDrawingBox = false;
            if(g_rectangle.width<0)
            {
                g_rectangle.x+=g_rectangle.width;
                g_rectangle.width *= -1;//乘以-1
            }
            if(g_rectangle.height<0)
            {
                g_rectangle.y+=g_rectangle.height;
                g_rectangle.height *= -1;
            }
            DrawRectangle(image,g_rectangle);
        }
            break;
    }
}

void DrawRectangle(cv::Mat &img, Rect box)
{
    rectangle(img,box.tl(),box.br(),Scalar(g_rng.uniform(0,255),g_rng.uniform(0,255),g_rng.uniform(0,255)));// 随机颜色
}



12、Mat的深复制和浅复制

Mat A,C;// 仅创建信息头部分
A = imread("1.jpg",CV_LOAD_IMAAGE_COLOR);// 这里为矩阵开辟内存
Mat B(A);// 使用拷贝构造函数(指针指向同一个矩阵)
C = A;// 这里ABC都是指向同一个内存

// 以下两个方法都是共享矩阵(内存),而且指定了范围
Mat D(A,Rect(10,10,100,100));// 使用矩形界定
Mat E = A(Range:all(),Range(1,3));// 使用行列界定

// 使用clone和copyTo则完全复制,指向不同的内存
Mat F = A.clone();
Mat G;
A.copyTo(G);

13、显式创建Mat的方法

(1)使用Mat()构造函数

    Mat M(2,2,CV_8UC3,Scalar(0,0,255));
    // 2,2即2行2列
    // CV_8UC3公式:CV_[位数][带符号否][类型前缀][通道数]
    // 8UC3即:使用8位的unsigned char型,每个像素由3个元素组成3通道
    // Scalar是个short型的向量,可以用他表示一个颜色(即3通道)
    // 输出:
    cout<<"M="<

输出:

M=
 [  0,   0, 255,   0,   0, 255;
   0,   0, 255,   0,   0, 255]

由此可见,Mat的矩阵就是:

[x,y,z,x,y,z,x,y,z;
 x,y,z,x,y,z,x,y,z]

这样连起来,换行用分号。

(2)用create创建

    Mat M;
    M.create(4,4,CV_8UC2);
    cout<<"M="<
 [ 64, 210, 119,  98,  80, 210, 119,  98;
  96, 210, 119,  98, 224, 207, 119,  98;
 240, 207, 119,  98,   0, 208, 119,  98;
  16, 208, 119,  98,  32, 208, 119,  98]

14、python风格的输出(每个像素会有中括号)

    Mat r = Mat(10,3,CV_8UC3);
    randu(r,Scalar::all(0),Scalar::all(255));

    cout<<"r(PythonStyle)="<
r(PythonStyle)=[[[ 91,   2,  79], [179,  52, 205], [236,   8, 181]],
 [[239,  26, 248], [207, 218,  45], [183, 158, 101]],
 [[102,  18, 118], [ 68, 210, 139], [198, 207, 211]],
 [[181, 162, 197], [191, 196,  40], [  7, 243, 230]],
 [[ 45,   6,  48], [173, 242, 125], [175,  90,  63]],
 [[ 90,  22, 112], [221, 167, 224], [113, 208, 123]],
 [[214,  35, 229], [  6, 143, 138], [ 98,  81, 118]],
 [[187, 167, 140], [218, 178,  23], [ 43, 133, 154]],
 [[150,  76, 101], [  8,  38, 238], [ 84,  47,   7]],
 [[117, 246, 163], [237,  69, 129], [ 60, 101,  41]]]

15、颜色的直观感受

颜色与RGB数值,数值越小,颜色越深;数值越大颜色越浅。

三个数值线性变化则颜色会呈明暗变化,但是色相基本不变。

Opencv学习笔记(总结)_第1张图片


16、颜色空间缩减

    // ______________颜色空间缩减原理________________
    // 注意:此处颜色空间缩减,并非能减少图片在内存中占用空间的意思。
    // 此处的意思是,如果我们需要把图片的所有点的数据取出来进行操作处理,如果我们用此缩减的方法,那么存放这些用来处理的数据可以更精简
    // 此处非图片压缩之意,而是缩减我们的处理数据

    // 颜色每个通道有0~255共256个数,由于数值相近则颜色非常相近,我们用近似取法,即:
    // 0~9的数取0
    // 10~19的数取10
    // ...
    // 这样做其实这个颜色偏差不大,但是数据量就少了很多
    // 可以这样理解:颜色有256种,256种之间区别很精细。我们缩减到26种,就是颜色没有分的那么精细了,但是在某些情况下还是可用。
    // 只要这样:颜色数值/10*10,就可以了比如136,136/10即13,余数6自动被丢弃,再乘以10,则变成130.
    // 即我们只需要:0,10,20,30,40,50,60,70,80,90,100,110,120,130,140,150,160,170,180,190,200,210,220,230,240,250.
    // 我们可以做一个这样的对应表:256个颜色给他分别对应到26个颜色里面,这样就不需要再计算了。

    int divideWith = 10;
    uchar table[256];
    for(int i = 0;i<256;i++)
        table[i] = divideWith*(i/divideWith);
    // 注意这个table:
    // table[0] = 0;
    // table[1] = 0;
    // table[2] = 0;
    // table[3] = 0;
    // ...
    // table[10] = 10;
    // table[11] = 10;
    // table[12] = 10;
    // ...
    // table[20] = 20;
    // table[21] = 20;
    // ...
    // ...
    // table[250] = 250;
    // table[251] = 250;
    // table[252] = 250;
    // ...
    // 可见这个talbe已经天然的完成了一个映射关系,他的下标跟值的映射
    // p[j] = table[p[j]];// 颜色值变成table的下标,取对应下标的值


    // 用LUT函数
    Mat lookUpTable(1,256,CV_8U);
    uchar * p = lookUpTable.data;
    for(int i = 0;i<256;i++)
        p[i] = table[i];// 把数据装到p,改变了p其实也改变了lookUpTable
    // 然后就可以用LUT函数了,
    LUT(I输入图片Mat,lookUpTable,J输出图片Mat);// 直接全图全转了

17、操作图片像素的三种方法示例

#include 
#include 
#include 
#include 

#pragma execution_character_set("utf-8")

using namespace cv;
using namespace std;

void colorReduceByPointer(Mat & inputImage,Mat & outputImage,int div);

void colorReduceByIterator(Mat & inputImage,Mat & outputImage,int div);

void colorReduceByAddr(Mat & inputImage,Mat & outputImage,int div);

int main(int argc,char ** argv)
{
    Mat srcImage = imread("dota.jpg");

    namedWindow("原始图像");

    imshow("原始图像",srcImage);

    Mat dstImage;

    dstImage.create(srcImage.rows,srcImage.cols,srcImage.type());// 大小类型要相同

    double time0 = static_cast(getTickCount());

//    colorReduce(srcImage,dstImage,32);

//    colorReduceByIterator(srcImage,dstImage,32);

    colorReduceByAddr(srcImage,dstImage,32);

    time0 = ((double)getTickCount()-time0)/getTickFrequency();
    cout<<"this method run time is:"<(i);//获取第i行首地址
        if(i == 1)
        {
            cout<<"data[1]="<    Mat srcImage1 = imread("dota_pa.jpg");
    Mat logoImage = imread("dota_logo.jpg");
    if(!srcImage1.data)
    {
        printf("read image1 error!");
        return 0;
    }
    if(!logoImage.data)
    {
        printf("read image2 error!");
        return 0;
    }

    Mat imageROI = srcImage1(Rect(200,50,logoImage.cols,logoImage.rows));

    Mat mask = imread("dota_logo.jpg",1);// 加载掩膜,书上说必须是灰度图,经测试此参数任意值都是可以的,缺省也可以

    logoImage.copyTo(imageROI);// 书上写:logoImage.copyTo(imageROI,mask);经测试可以不要mask

    namedWindow("window1");

    imshow("window1",srcImage1);

19、线性叠加:addWeight

    double alphaValue = 0.2;
    double betaValue;
    Mat srcImage2,srcImage3,dstImage;

    srcImage2 = imread("mogu.jpg");
    srcImage3 = imread("rain.jpg");

    if(!srcImage2.data)
    {
        printf("load image2 error!");
        return 0;
    }
    if(!srcImage3.data)
    {
        printf("load image3 error!");
        return 0;
    }

    betaValue = (1.0 - alphaValue);

    addWeighted(srcImage2,alphaValue,srcImage3,betaValue,0.0,dstImage);// 两个图片叠加并配置透明比重

    namedWindow("原图",1);

    imshow("原图",srcImage2);

    namedWindow("效果图",1);

    imshow("效果图",dstImage);

20、线性混合综合示例:

#include 
#include 
#include 
#include 

#pragma execution_character_set("utf-8")

using namespace cv;
using namespace std;

bool ROI_AddImage();
bool LinearBlending();
bool ROI_LinearBlending();


int main(int argc,char ** argv)
{
    system("color 5E");

    if(ROI_AddImage()&&LinearBlending()&&ROI_LinearBlending())
    {
        cout<

21、通道分离、合并

//--------------------------------------【程序说明】-------------------------------------------
//		程序说明:《OpenCV3编程入门》OpenCV2版书本配套示例程序26
//		程序描述:分离颜色通道&多通道图像混合
//		开发测试所用IDE版本:Visual Studio 2010
//		开发测试所用OpenCV版本:	3.0 beta
//		2014年11月 Created by @浅墨_毛星云
//		2014年12月 Revised by @浅墨_毛星云
//------------------------------------------------------------------------------------------------

//-----------------------------------【头文件包含部分】---------------------------------------
//	描述:包含程序所依赖的头文件
//------------------------------------------------------------------------------------------------
#include 
#include 
#include 

//-----------------------------------【命名空间声明部分】---------------------------------------
//	描述:包含程序所使用的命名空间
//-------------------------------------------------------------------------------------------------
using namespace cv;
using namespace std;


//-----------------------------------【全局函数声明部分】--------------------------------------
//	描述:全局函数声明
//-----------------------------------------------------------------------------------------------
bool  MultiChannelBlending();
void ShowHelpText();


//-----------------------------------【main( )函数】------------------------------------------
//	描述:控制台应用程序的入口函数,我们的程序从这里开始
//-----------------------------------------------------------------------------------------------
int main(   )
{
    system("color 9F");

    ShowHelpText( );

    if(MultiChannelBlending( ))
    {
        cout< channels;
    Mat  imageBlueChannel;

    //=================【蓝色通道部分】=================
    //	描述:多通道混合-蓝色分量部分
    //============================================

    // 【1】读入图片
    logoImage= imread("dota_logo.jpg",0);
    srcImage= imread("dota_jugg.jpg");

    if( !logoImage.data ) { printf("Oh,no,读取logoImage错误~! \n"); return false; }
    if( !srcImage.data ) { printf("Oh,no,读取srcImage错误~! \n"); return false; }

    //【2】把一个3通道图像转换成3个单通道图像
    split(srcImage,channels);//分离色彩通道

    //【3】将原图的蓝色通道引用返回给imageBlueChannel,注意是引用,相当于两者等价,修改其中一个另一个跟着变
    imageBlueChannel= channels.at(0);
    //【4】将原图的蓝色通道的(500,250)坐标处右下方的一块区域和logo图进行加权操作,将得到的混合结果存到imageBlueChannel中
    addWeighted(imageBlueChannel(Rect(500,250,logoImage.cols,logoImage.rows)),1.0,
        logoImage,0.5,0,imageBlueChannel(Rect(500,250,logoImage.cols,logoImage.rows)));

    //【5】将三个单通道重新合并成一个三通道
    merge(channels,srcImage);

    //【6】显示效果图
    namedWindow(" <1>游戏原画+logo蓝色通道");
    imshow(" <1>游戏原画+logo蓝色通道",srcImage);


    //=================【绿色通道部分】=================
    //	描述:多通道混合-绿色分量部分
    //============================================

    //【0】定义相关变量
    Mat  imageGreenChannel;

    //【1】重新读入图片
    logoImage= imread("dota_logo.jpg",0);
    srcImage= imread("dota_jugg.jpg");

    if( !logoImage.data ) { printf("读取logoImage错误~! \n"); return false; }
    if( !srcImage.data ) { printf("读取srcImage错误~! \n"); return false; }

    //【2】将一个三通道图像转换成三个单通道图像
    split(srcImage,channels);//分离色彩通道

    //【3】将原图的绿色通道的引用返回给imageBlueChannel,注意是引用,相当于两者等价,修改其中一个另一个跟着变
    imageGreenChannel= channels.at(1);
    //【4】将原图的绿色通道的(500,250)坐标处右下方的一块区域和logo图进行加权操作,将得到的混合结果存到imageGreenChannel中
    addWeighted(imageGreenChannel(Rect(500,250,logoImage.cols,logoImage.rows)),1.0,
        logoImage,0.5,0.,imageGreenChannel(Rect(500,250,logoImage.cols,logoImage.rows)));

    //【5】将三个独立的单通道重新合并成一个三通道
    merge(channels,srcImage);

    //【6】显示效果图
    namedWindow("<2>游戏原画+logo绿色通道");
    imshow("<2>游戏原画+logo绿色通道",srcImage);



    //=================【红色通道部分】=================
    //	描述:多通道混合-红色分量部分
    //============================================

    //【0】定义相关变量
    Mat  imageRedChannel;

    //【1】重新读入图片
    logoImage= imread("dota_logo.jpg",0);
    srcImage= imread("dota_jugg.jpg");

    if( !logoImage.data ) { printf("Oh,no,读取logoImage错误~! \n"); return false; }
    if( !srcImage.data ) { printf("Oh,no,读取srcImage错误~! \n"); return false; }

    //【2】将一个三通道图像转换成三个单通道图像
    split(srcImage,channels);//分离色彩通道

    //【3】将原图的红色通道引用返回给imageBlueChannel,注意是引用,相当于两者等价,修改其中一个另一个跟着变
    imageRedChannel= channels.at(2);
    //【4】将原图的红色通道的(500,250)坐标处右下方的一块区域和logo图进行加权操作,将得到的混合结果存到imageRedChannel中
    addWeighted(imageRedChannel(Rect(500,250,logoImage.cols,logoImage.rows)),1.0,
        logoImage,0.5,0.,imageRedChannel(Rect(500,250,logoImage.cols,logoImage.rows)));

    //【5】将三个独立的单通道重新合并成一个三通道
    merge(channels,srcImage);

    //【6】显示效果图
    namedWindow("<3>游戏原画+logo红色通道 ");
    imshow("<3>游戏原画+logo红色通道 ",srcImage);

    return true;
}






你可能感兴趣的:(opencv)