zoukankan      html  css  js  c++  java
  • 2、图像处理基础

    回顾

    Mat

    行 列 通道  维度

    row col channel dim

    在opencv里面的维度一定是大于等于2的,比如上面的一个行向量就是一个1*7的“二维向量”。

    在Mat里面除了上面四个比较常用的量以外,还有flag变量,它是在Mat 的头里面,包含了图像的维度,深度(是short类型、char类型还是double类型的);除了flag还有一个data的指针,它是指向内存中数据所在地址的;还有一个refcount指针,引用计数指针,看有多少指针指向了这个地址。

    第二讲的内容开始

    在Mat中有一个data指针,data指针指向的是数据在内存中的首地址,

    M.step[1]为每一行的列元素的大小!!!

    由于上面的行和列表达起来有歧义,故其row和col都表示为-1.上面的矩阵为3*4*6的矩阵。

    上面的step[0]为一个面的大小,为4*6*(4*16/8)=192bytes

    step[1]为6*(4*16/8)=48

    step[2]为4*(16/8)=8

    例子:

    Mat m(400,400,CV_8U,Scalar(0));

    定义一个单通道的400*400大小的矩阵,矩阵元素初值为0,即全黑的图像

    #include <iostream>
    
     #include<highgui.h> 
    
    #include "opencv2/opencv.hpp" 
    
    using namespace cv; 
    
    using namespace std;
    
    int main(int argc, char* argv[])
    
    {
    
    Mat m(400,400,CV_8U,Scalar(0));
     for (int col = 0; col < 400; col++)
     {
      for (int row = 195; row < 205; row++)
      {
       cout << (int)(*(m.data + m.step[0] * row + m.step[1] * col)) << "  ==>";
       //获取第[row,col]个像素点的地址并用*符号解析
       *(m.data + m.step[0] * row + m.step[1] * col) = 255;
       cout << (int)(*(m.data + m.step[0] * row + m.step[1] * col)) << endl;
      }
     }
     imshow("canvas",m);
     cvWaitKey();
     getchar();
     return 0;
    }
    View Code

    例子:

    Vec3i color定义一个变量,它是Vector类型的,有3个元素,且是int型的;

    注意cvWaitKey()可以传参,单位是毫秒;

    #include <iostream> #include<highgui.h> 
    
    #include "opencv2/opencv.hpp" 
    
    using namespace cv;
    
     using namespace std;
    
    int main(int argc, char* argv[])
    
     {
    
    Mat m = imread("lena.jpg");
     int *p_address;
     Vec3i color;
     for (int col = 20; col < 40; col++)
     {
      for (int row = 2; row < 20; row++)
      {
       color[0] = (int)(*(m.data+m.step[0]*row+m.step[1]*col));
       color[1] = (int)(*(m.data + m.step[0] * row + m.step[1] * col+m.elemSize1()));
       color[2] = (int)(*(m.data + m.step[0] * row + m.step[1] * col + m.elemSize1()*2));
       //获取第[row,col]个像素点的地址并用*符号解析
       cout << color[0] << "," << color[1] << "," << color[2] << "  ==>";
       color[0] = 255;
       color[1] = 0;
       color[2] = 0;
       *(m.data + m.step[0] * row + m.step[1] * col) = color[0];
       *(m.data + m.step[0] * row + m.step[1] * col + m.elemSize1()) = color[1];
       *(m.data + m.step[0] * row + m.step[1] * col + m.elemSize1() * 2) = color[2];
       cout << (int)(*(m.data + m.step[0] * row + m.step[1] * col)) << (int)(*(m.data + m.step[0] * row + m.step[1] * col + 1)) << (int)(*(m.data + m.step[0]*row + m.step[1] * col + 2)) << endl;
      }
     }
     imshow("canvas",m);
     cvWaitKey();
     getchar();
     return 0;
    }

    结果:

    上面的数据类型是错误的!!!!!

    opencv的模板类Mat_类

    例子:

    #include <iostream>
    
     #include<highgui.h>
    
     #include "opencv2/opencv.hpp" 
    
    using namespace cv; 
    
    using namespace std;
    
    int main(int argc, char* argv[]) {
    
    Mat m = imread("lena.jpg");
     Mat_<Vec3b> m2 = m;
     //for()循环画一个红色的实心圆
     for (int y = 21; y < 42; y++)
     {
      for (int x = 2; x < 21; x++)
      {
       if (pow(double(x - 11), 2) + pow(double(y - 31), 2) - 64.0 < 0.00000000001)
       {
        //Mat_模板类实现了对()的重载,可以定位到一个像素
        m2(x, y) = Vec3b(0,0,255);
       }
      }
     }imshow("canvas",m);
     cvWaitKey();
     getchar();
     return 0;
    }
    View Code

    结果如下:

    注意pow函数的含义:pow(src,double p,dst);//如果p是整数dst(I)=src(I)^p;其他|src(I)|^p

    像素值的读写6

    上面是进行图像的量化,把原来的像素点(之前是0-255),现在不需要那么高的像素级,把它降低10个等级,原来的像素级除以10再乘以10;

    查找表,在上面先定义了一个uchar型的数组,uchar table[256];然后再进行像素量化降级,可以对比用二值图像来理解,然后再建立一个1*256的一个数组lookuptable。LUT(源图像输入,查找表,输出图像)。它只有在有映射关系的时候才能用到,是一个特例。

    在2.4以前,有这两种数据类型IplImage和CvMat,我们现在都用Mat,然后有一些例程,它的形式是IplImage *p,这种图像指针类型的,我们可以用&iplimg这种引用的方式转换为Mat类型。

    同时也支持这两种方式互转,

    关于图像的读取

    Mat imread(const string &filename,int flags=1)

    imread()函数,返回值是一个Mat类型,它读取失败里面的*data是指向NULL的,建议不要使用指针来判断是否为NULL来说明是否读取成功;它自己有一个成员函数来判断的isempty();

    flags只要大于0就代表返回3通道图像,灰度图像就会强制转化为3通道,flag为0,强制转化为单通道;flag小于0,那么是什么就读什么,不进行转换;

    有一种图像格式叫做PNM,PPM,PGM,可移植像素格式,它是纯文本的格式,常见的是PGM的格式;

    imwrite()是存储文件

    注意并不是所有的Mat都可以存储成图像,目前只支持8U的单通道或者3通道格式,如果想把16U的转换成功的话,就只能用PNG格式或者JPEG2000,注意一下。

    如果这个文件夹下有这个文件,它是直接覆盖的,不会有任何提醒;

    首先来看看imwrite()函数的具体用法。

      bool imwrite(const string& filename, InputArray img, const vector<int>& params=vector<int>() )

      该函数是把程序中的Mat类型的矩阵保存为图像到指定位置。

      参数filename为所需保存图像的文件目录和文件名。这里的文件名需要带有图像格式后缀的,目前OpenCV该函数只支持JPEG,PNG,PPM,PGM,PBM,TIFF等。并不是所有Mat类型都支持。

      img参数为图像数据来源,其类型为Mat。注意也不是所有格式的Mat型数据都能被使用保存为图片,目前OpenCV主要只支持单通道和3通道的图像,并且此时要求其深度为8bit和16bit无符号(即CV_16U)。所以其他一些数据类型是不支持的,比如说float型等。如果Mat类型数据的深度和通道数不满足上面的要求,则需要使用convertTo()函数和cvtColor()函数来进行转换。convertTo()函数负责转换数据类型不同的Mat,即可以将类似float型的Mat转换到imwrite()函数能够接受的类型。而cvtColor()函数是负责转换不同通道的Mat,因为该函数的第4个参数就可以设置目的Mat数据的通道数(只是我们一般没有用到它,一般情况下这个函数是用来进行色彩空间转换的)。另外也可以不用imwrite()函数来存图片数据,可以直接用通用的XML IO接口函数将数据存在XML或者YXML中。

      参数params是用来设置对应图片格式的参数的,因为一般情况下这些图片格式都是经过了压缩的,这里就是设置这些压缩参数来控制图片的质量。该参数是一个vector<int>类型,里面分别存入paramId_1, paramValue_1, paramId_2, paramValue_2, ... 也就是说存入一对属性值。如果不设置该参数的话,则程序会自动根据所保存的图像格式采用一个默认的参数。

    介绍一下,打开外设,或者读取视频的一个例子

    VideoCapture这样一个类,有一个构造函数直接指定设备的编号cap(0);注意在工程的时候通过hub连接两个或者更多的时候,其ID可能就会是同一个,出现打不开的情况。

    #include<iostream>
    #include"opencv2/opencv.hpp"
    #include<stdio.h>
    using namespace std;
    using namespace cv;
    int main(int argc, char *argv[])
    {
     //打开摄像头
     VideoCapture cap(0);
     //打开视频文件 
     //VideoCapture cap("video.short.raw.avi");
     //检查是否成功打开
     if (!cap.isOpened())
     {
      cerr << "can not open a camera or file."<<endl;
      return -1;
     }
     Mat edges;
     //创建窗口
     namedWindow("edges",1);
     for (;;)
     {
      Mat frame;
      //从cap中读一帧,存到frame
      cap >> frame;
      //如果未读到图像
      if (frame.empty())
       break;
      //将读到的图像转为灰度图
      cvtColor(frame,edges,CV_BGR2GRAY);
      //进行边缘提取操作
      Canny(edges,edges,0,30,3);
      //显示结果
      imshow("edges",edges);
      //等待30s,如果按键则退出循环
      if (waitKey(30) >= 0)
       break;
     }
     //退出时会自动释放 cap 中占用资源 
     return 0;
    }
    View Code

    上面的例子是读下面的例子是写

    #include<iostream>
    #include"opencv2/opencv.hpp"
    #include<stdio.h>
    using namespace std;
    using namespace cv;
    int main(int argc, char *argv[])
    {
     //定义视频的宽度和高度
     Size s(320, 240);
     //创建writer,并制定FOURCC及FPS等参数
     VideoWriter writer = VideoWriter("myvedio.avi",CV_FOURCC('M','J','P','G'),25,s);
     //检查是否成功创建
     if (!writer.isOpened())
     {
      cerr << "Can not create video file.
    "<<endl;
      return -1;
     }
     //视频帧
     Mat frame(s,CV_8UC3);
     for (int i = 0; i < 100; i++)
     {
      //将图像置为黑色
      frame = Scalar::all(0);
      //将整数i转为i字符串类型
      char text[128];
      sprintf_s(text,"%d",i);
      //将数字绘到画面上
      putText(frame,text,Point(s.width/3,s.height/3),FONT_HERSHEY_SCRIPT_SIMPLEX,3,Scalar(0,0,255),3,8);
      //将图像写入视频
      writer << frame;
     }
     VideoCapture cap("myvedio.avi");
     for (int i = 0; i < 100; i++)
     {
      Mat frame;
      //从 cap 中读一帧,存到 frame 
      cap >> frame;
      //如果未读到图像 
      if (frame.empty())
       break;
      //显示结果 
      imshow("frame", frame);
      waitKey(1000);
     }
     //退出程序时自动关闭视频文件
     waitKey(0);
     return 0;
    }
    View Code

     

    本课程涉及到深度学习与机器学习相关的内容,所以要学习一下python

     python环境的安装,建议Anaconda+Ipython+(PyScripter)(版本2.7比较流行或者3.5都可以)

    print函数在2.7没有括号,在3.5有括号

    在2.7版本

    x=3,x/2=1,是整型

    在3.5版本

    x=3,x/2=1.5是浮点型

    机器学习

    机器学习:要随机得观测数据,要随机得对观测数据进行采样,要学习数据的性质,其实也叫做特征feature,以及属性,属性通常叫做label,他是属于那一个类别,再来预测新的未知的数据的属性。在机器学习当中,我们通常要把数据分成两部分,一部分叫做training(训练集用来学习数据特征),另一部分叫做test(测试集用来测试算法是否准确)。机器学习的问题主要分为

    监督学习和非监督学习

    监督学习除了数据本身以外,还有额外的属性部分,也就是说会有一些feature,然后再额外的会有一些label,这样的问题分为分类和回归两部分;分类问题可以理解为输出是离散数据;回归问题输出的就是连续的,比如说根据年龄、体重,来预测身高。监督学习主要是分类,尽量把问题转化为分类问题。

    如果输入没有额外的label等,那么就叫做非监督学习,主要分为聚类(kmeans)和核密度估计。

    Knn-Grassroots Democracy

    当有一个未知物体的时候,在我们做出推荐之前会考虑一下它周围的数据的label是属于那个类别,从而觉得这个数据是属于那个类别的。

    KNN算法应用得背景是字符识别,最常见的数据库在网站http://yann.lecun.com/exdb/mnist

    knn作为一种机器学习算法也分为两部分,训练算法识别特征的类别,然后在训练集上测试;KNN的训练部分就是把训练集和标签全部存储,比如说,给出5这样一个训练的图像

    它的label就是5。会有一个其他图片比如说是0,它的label就是0,

    KNN就会把这两个属性全都存储下来,它就学习完了,只要把数据全部喂给算法,它就已经完成识别了,什么操作都没有,接下来就是测试部分,只要提供测试集,没有标签,在指定K的大小之后,让算法来猜它是什么数据。它是没有训练的,平时不学习,等到测试的时候问题就来了,它就把所有的训练集跟测试数据进行一一比对,比对就涉及到一个距离问题,测试两个向量的距离distance。

    下面将一下聚类算法

    上面图在轮廓上是比较相似的,但是在语义上是不同的。

    讲到聚类算法必须提到K-means算法

  • 相关阅读:
    jquery实现短信群发功能(机试题)
    PreparedStatement与Statement区别
    java中static关键字
    java笔试01
    java基础
    sqlserver errorcode
    改变分辨率会牵连到EMF图的大小
    基础知识——各种分辨率的知识 From http://vod.sjtu.edu.cn/help/Article_Show.asp?ArticleID=308
    本地存储
    Silverlight 3 MultiThreading编程http://blog.csdn.net/zjfei/archive/2009/07/27/4384428.aspx
  • 原文地址:https://www.cnblogs.com/gary-guo/p/6274820.html
Copyright © 2011-2022 走看看