首页 > 编程语言 >OpenCV4之C++入门详解

OpenCV4之C++入门详解

时间:2022-12-02 15:24:28浏览次数:63  
标签:Mat int demo image C++ 详解 OpenCV4 include void

OpenCV4之C++入门详解

1、Visual Studio安装及环境配置与搭建

1.下载地址:https://my.visualstudio.com/Downloads?q=Visual,下载后按照说明安装即可

登录账号下载即可,建议下载Visual Studio 2017 专业版,本教程使用该版本完成
该教程笔记是本人整理的OpenCV学堂视频教程内容,感谢贾志刚老师的视频教程,下面是OpenCV 4.5.4及源码下载链接

链接:https://pan.baidu.com/s/1HmWrX35P774rr6tlfUXB2A 提取码:urtd

2.配置系统环境变量,鼠标右键我的电脑,选择属性,之后按下图操作,复制opencv目录下的bin目录,vs2017选择vc15

image.png

3.安装完毕后,新建第一个项目如下图

image.png

4.右键源文件选择新建项新建一个main.cpp

image.png

image.png

5.添加包含目录、库目录及附加依赖项

image.png

image.png

image.png

image.png

image.png

6.在D盘下新建一个images文件夹,放入一张图片,图片名与下面代码段中的图片名字一致

image.png

7.在main.cpp中输入以下代码

#include<opencv2/opencv.hpp>
#include<iostream>
using namespace cv;
using namespace std;
int main(int argc, char**argv) {
  Mat src = imread("D:/images/lena.jpg");
  imshow("input", src);
  waitKey(0);
  destroyAllWindows();
  return 0;
}

8.点击 调试开始调试 ,如果出现下图则表示运行成功,配置成功

image.png

至此,Visual Studio的准备工作完成!

2、图像基本操作

多行注释快捷键:Ctrl + K + Ctrl + C

2.1、图像读取与显示

#include<opencv2/opencv.hpp>
#include<iostream>
using namespace cv;
using namespace std;
int main(int argc, char**argv) {
    //imread函数的第二个参数有很多,默认为IMREAD_COLOR,还有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,实现对不同图片的读取操作
  Mat src = imread("D:/images/lena.jpg",IMREAD_GRAYSCALE);    //Mat为matrix,二维图像都是Mat类型,第一个参数为图片绝对路径
  if (src.empty()){
    printf("could not load image...\n");
    return -1;
  }
  namedWindow("输入窗口",WINDOW_FREERATIO);   //不管图片大小,都能进行调整,图像很小可以不使用这个函数
  imshow("输入窗口", src);                    //第一个参数为窗口名,imshow()只支持显示8位图像及浮点图像
  waitKey(0);                               //窗口停留时间,0为一直停留,数值为停留的毫秒数
  destroyAllWindows();                      //关闭所有打开的窗口
  return 0;
}

2.2、图像色彩空间转换

新建一个头文件quickopencv.h

#pragma once
#include<opencv2/opencv.hpp>
using namespace cv;
class QuickDemo {
  public:
    void colorSpace_Demo(Mat &image);
};

添加该项目包含目录为当前文件夹,操作如下

image.png

image.png

image.png

新建一个源文件quickdemo.cpp

#include<quickopencv.h>
void QuickDemo::colorSpace_Demo(Mat &image) {
  Mat gray, hsv;
  cvtColor(image, hsv, COLOR_BGR2HSV);
  // H 0~180 S 0~255 V 0~255
  cvtColor(image, gray, COLOR_BGR2GRAY);
  imshow("HSV", hsv);
  imshow("灰度", gray);
  imwrite("D:/images/hsv.png", hsv);
  imwrite("D:/images/gray.png", gray);
}

修改源文件test440,进行调试

#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>
using namespace cv;
using namespace std;
int main(int argc, char**argv) 
{
  //imread函数的第二个参数有很多,默认为IMREAD_COLOR,还有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,实现对不同图片的读取操作
  // B,G,R
  Mat src = imread("D:/images/lena.jpg");   //Mat为matrix,二维图像都是Mat类型,第一个参数为图片绝对路径
  if (src.empty())
  {
    printf("could not load image...\n");
    return -1;
  }
      //namedWindow("输入窗口", WINDOW_FREERATIO);   
    //不管图片大小,都能进行调整,图像很小可以不使用这个函数
    
  imshow("输入窗口", src);                    //第一个参数为窗口名
    
    //引入类QuickDemo,调用方法
  QuickDemo qd;
  qd.colorSpace_Demo(src);
  waitKey(0);                               //窗口停留时间,0为一直停留,数值为停留的毫秒数
  destroyAllWindows();                      //关闭所有打开的窗口
  return 0;
}

效果

image.png

2.3、图像对象的创建与赋值

quickopencv.h

#pragma once
#include<opencv2/opencv.hpp>
using namespace cv;
class QuickDemo {
  public:
    void colorSpace_Demo(Mat &image);
    void mat_creation_demo();
};

quickdemo.cpp

#include<quickopencv.h>
void QuickDemo::colorSpace_Demo(Mat &image) {
  Mat gray, hsv;
  cvtColor(image, hsv, COLOR_BGR2HSV);
  // H 0~180 S 0~255 V 0~255
  cvtColor(image, gray, COLOR_BGR2GRAY);
  imshow("HSV", hsv);
  imshow("灰度", gray);
  imwrite("D:/images/hsv.png", hsv);
  imwrite("D:/images/gray.png", gray);
}
void QuickDemo::mat_creation_demo() {
  //克隆和复制才会创建新的对象,赋值不会创建新的对象
  //Mat m1, m2;
  //m1 = image.clone();
  //image.copyTo(m2);
  // 创建空白图像
  Mat m3 = Mat::ones(Size(512, 512), CV_8UC3);
  m3 = Scalar(127, 127, 127); // 为像素赋予指定的值 B,G,R顺序
  std::cout << "width: " << m3.cols << " height: " << m3.rows << " channels: " << m3.channels() << std::endl;
  //std::cout << m3 << std::endl;
  Mat m4 = m3; //赋值后m4改变,会引起m3改变,clone或copyTo则会创建新对象,不影响原对象
  m4 = Scalar(0, 255, 255);
  imshow("创建图像", m3);
  Mat kernel = (Mat_<char>(3, 3) << 0,-1,0, // 3*3卷积核
    -1,5,-1,
    0,-1,0);
}

test440.cpp

#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>
using namespace cv;
using namespace std;
int main(int argc, char**argv)
{
  // imread函数的第二个参数有很多,默认为IMREAD_COLOR,还有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,实现对不同图片的读取操作
  // B,G,R
  Mat src = imread("D:/images/lena.jpg");   //Mat为matrix,二维图像都是Mat类型,第一个参数为图片绝对路径
  if (src.empty())
  {
    printf("could not load image...\n");
    return -1;
  }
  //namedWindow("输入窗口", WINDOW_FREERATIO);   //不管图片大小,都能进行调整,图像很小可以不使用这个函数
  imshow("输入窗口", src);                    //第一个参数为窗口名
  QuickDemo qd;
  qd.mat_creation_demo();
  waitKey(0);                               //窗口停留时间,0为一直停留,数值为停留的毫秒数
  destroyAllWindows();                      //关闭所有打开的窗口
  return 0;
}

效果

image.png

2.4、图像像素的读写操作

quickopencv.h

#pragma once
#include<opencv2/opencv.hpp>
using namespace cv;
class QuickDemo
{
  public:
    void colorSpace_Demo(Mat &image);
    void mat_creation_demo();
      void pixel_visit_demo(Mat &image);
};

quickdemo.cpp

#include<quickopencv.h>
void QuickDemo::pixel_visit_demo(Mat &image) {
  int w = image.cols;
  int h = image.rows;
  int dims = image.channels();
  //for (int row = 0; row < h; row++) {
  //  for (int col = 0; col < w; col++) {
  //    if (dims == 1) { //灰度图像
  //      int pv = image.at<uchar>(row, col); //row,col → y,x
  //      image.at<uchar>(row, col) = 255 - pv; //对像素值反转,image.at<uchar>为获取某点格式为uchar的像素值
  //    }
  //    if (dims == 3) { //彩色图像
  //      Vec3b bgr = image.at<Vec3b>(row, col); //Vec3b为bgr图像像素点存储格式,对像素值进行反转
  //      image.at<Vec3b>(row, col)[0] = 255 - bgr[0];
  //      image.at<Vec3b>(row, col)[1] = 255 - bgr[1];
  //      image.at<Vec3b>(row, col)[2] = 255 - bgr[2];
  //    }
  //  }
  //}
  for (int row = 0; row < h; row++) {
    uchar* current_row = image.ptr<uchar>(row); //获取当前行最初位置的指针
    for (int col = 0; col < w; col++) {
      if (dims == 1) { //灰度图像
        int pv = *current_row;
        *current_row++ = 255 - pv; //每次运算完,指针右移一位
      }
      if (dims == 3) { //彩色图像
        *current_row++ = 255 - *current_row; //由于bgr图像矩阵是连续的,所以指针直接指向下一位
        *current_row++ = 255 - *current_row;
        *current_row++ = 255 - *current_row;
      }
    }
  }
  imshow("像素读写演示", image);
}

test440.cpp

#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>
using namespace cv;
using namespace std;
int main(int argc, char**argv) {
  // imread函数的第二个参数有很多,默认为IMREAD_COLOR,还有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,实现对不同图片的读取操作
  // B,G,R
  Mat src = imread("D:/images/lena.jpg");   //Mat为matrix,二维图像都是Mat类型,第一个参数为图片绝对路径
  if (src.empty()) {
    printf("could not load image...\n");
    return -1;
  }
  //namedWindow("输入窗口", WINDOW_FREERATIO);   //不管图片大小,都能进行调整,图像很小可以不使用这个函数
  imshow("输入窗口", src);                    //第一个参数为窗口名
  QuickDemo qd;
  qd.pixel_visit_demo(src);
  waitKey(0);                               //窗口停留时间,0为一直停留,数值为停留的毫秒数
  destroyAllWindows();                      //关闭所有打开的窗口
  return 0;
}

效果

image.png

2.5、图像像素的算数操作

quickopencv.h

#pragma once
#include<opencv2/opencv.hpp>
using namespace cv;
class QuickDemo {
  public:
    void colorSpace_Demo(Mat &image);
    void mat_creation_demo();
      void pixel_visit_demo(Mat &image);
      void operators_demo(Mat &image);
};

quickdemo.cpp

#include<quickopencv.h>
void QuickDemo::operators_demo(Mat &image) {
  Mat dst;
  Mat m = Mat::zeros(image.size(), image.type());
  m = Scalar(2, 2, 2); //Scalar标量
  //dst = image + Scalar(50, 50, 50);
  //dst = image - Scalar(50, 50, 50);
  //dst = image / Scalar(2, 2, 2);
  //加法手写实现,主要使用saturate_cast函数,运算可使用对应函数快速实现
  /*
  int w = image.cols;
  int h = image.rows;
  int dims = image.channels();
  for (int row = 0; row < h; row++) {
    for (int col = 0; col < w; col++) {
      Vec3b p1 = image.at<Vec3b>(row, col);
      Vec3b p2 = m.at<Vec3b>(row, col);
      //saturate_cast函数,将大于255的数转换为255,小于0的数转换为0
      dst.at<Vec3b>(row, col)[0] = saturate_cast<uchar>(p1[0] + p2[0]);
      dst.at<Vec3b>(row, col)[1] = saturate_cast<uchar>(p1[1] + p2[1]);
      dst.at<Vec3b>(row, col)[2] = saturate_cast<uchar>(p1[2] + p2[2]);
    }
  }
  imshow("加法操作", dst);
  */
  //add(image, m, dst); //add(操作的图,对图片操作的参数,输出的结果)
  //subtract(image, m, dst); //减法
  //divide(image, m, dst); //除法
  multiply(image, m, dst); //乘法
  
  //imshow("加法操作", dst);
  //imshow("减法操作", dst);
  //imshow("除法操作", dst);
  imshow("乘法操作", dst);
}

test440.cpp

#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>
using namespace cv;
using namespace std;
int main(int argc, char**argv) {
  // imread函数的第二个参数有很多,默认为IMREAD_COLOR,还有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,实现对不同图片的读取操作
  // B,G,R
  Mat src = imread("D:/images/dark_face.jpg");   //Mat为matrix,二维图像都是Mat类型,第一个参数为图片绝对路径
  if (src.empty()) {
    printf("could not load image...\n");
    return -1;
  }
  //namedWindow("输入窗口", WINDOW_FREERATIO);   //不管图片大小,都能进行调整,图像很小可以不使用这个函数
  imshow("输入窗口", src);                    //第一个参数为窗口名
  QuickDemo qd;
  qd.operators_demo(src);
  waitKey(0);                               //窗口停留时间,0为一直停留,数值为停留的毫秒数
  destroyAllWindows();                      //关闭所有打开的窗口
  return 0;
}

效果

image.png

2.6、使用滚动条调整图像亮度(TrackBar)

quickopencv.h

#pragma once
#include<opencv2/opencv.hpp>
using namespace cv;
class QuickDemo {
  public:
    void colorSpace_Demo(Mat &image);
    void mat_creation_demo();
    void pixel_visit_demo(Mat &image);
    void operators_demo(Mat &image);
    void tracking_bar_demo(Mat &image);
};

quickdemo.cpp

Mat src, dst, m;
int lightness = 50;
//回调函数两个形参,第一个int为createTrackbar中当前滑块所在位置,初始为lightness,第二个为userdata,为createTrackbar最后一个参数,默认为0
static void on_track(int, void*) {
  m = Scalar(lightness, lightness, lightness);
  add(src, m, dst);
  imshow("亮度调整", dst);
}
void QuickDemo::tracking_bar_demo(Mat &image) {
  namedWindow("亮度调整", WINDOW_AUTOSIZE);
  dst = Mat::zeros(image.size(), image.type());
  m = Mat::zeros(image.size(), image.type());
  src = image;
  int max_value = 100;
  //createTrackbar(滑动条名,滑动条所在的窗口,滑动块初始位置,滑动条最大值,回调函数(滑块滑动时的处理))
  createTrackbar("Value Bar:", "亮度调整", &lightness, max_value, on_track); 
  on_track(50, 0);
}

test440.cpp

#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>
using namespace cv;
using namespace std;
int main(int argc, char**argv) {
  // imread函数的第二个参数有很多,默认为IMREAD_COLOR,还有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,实现对不同图片的读取操作
  // B,G,R
  Mat src = imread("D:/images/dark_face.jpg");   //Mat为matrix,二维图像都是Mat类型,第一个参数为图片绝对路径
  if (src.empty()) {
    printf("could not load image...\n");
    return -1;
  }
  //namedWindow("输入窗口", WINDOW_FREERATIO);   //不管图片大小,都能进行调整,图像很小可以不使用这个函数
  imshow("输入窗口", src);                    //第一个参数为窗口名
  QuickDemo qd;
  qd.tracking_bar_demo(src);
  waitKey(0);                               //窗口停留时间,0为一直停留,数值为停留的毫秒数
  destroyAllWindows();                      //关闭所有打开的窗口
  return 0;
}

效果

image.png

2.7、滚动条操作-通过参数传递度

quickopencv.h

#pragma once
#include<opencv2/opencv.hpp>
using namespace cv;
class QuickDemo {
  public:
    void colorSpace_Demo(Mat &image);
    void mat_creation_demo();
    void pixel_visit_demo(Mat &image);
    void operators_demo(Mat &image);
    void tracking_bar_demo(Mat &image);
};

quickdemo.cpp 对上一节函数优化

//回调函数两个形参,第一个int为createTrackbar中的当前滑块所在位置,第二个为userdata,为createTrackbar最后一个参数,默认为0
static void on_lightness(int b, void* userdata) {
  Mat image = *((Mat*)userdata);  //指针转换成Mat类型数据
  Mat dst = Mat::zeros(image.size(), image.type());
  Mat m = Mat::zeros(image.size(), image.type());
  addWeighted(image, 1.0, m, 0, b, dst);  //dst = image*1.0 + m*0 + b
  imshow("亮度与对比度调整", dst);
}
static void on_contrast(int b, void* userdata) {
  Mat image = *((Mat*)userdata);  //指针转换成Mat类型数据
  Mat dst = Mat::zeros(image.size(), image.type());
  Mat m = Mat::zeros(image.size(), image.type());
  double contrast = b / 100.0;
  //addWeighted()函数可以实现两张图片混合
  addWeighted(image, contrast, m, 0, 0, dst);  //dst = image*contrast + m*0 + 0
  imshow("亮度与对比度调整", dst);
}
void QuickDemo::tracking_bar_demo(Mat &image) {
  namedWindow("亮度与对比度调整", WINDOW_AUTOSIZE);
  int lightness = 50;
  int light_max_value = 100;
  int contrast_value = 100;
  int contrast_max = 200;
  //createTrackbar(滑动条名,滑动条所在的窗口,滑动块初始位置,滑动条最大值,回调函数(滑块滑动时的处理),userdata(传递给回调函数的数据))
  createTrackbar("Value Bar:", "亮度与对比度调整", &lightness, light_max_value, on_lightness, (void*)(&image));
  createTrackbar("Contrast Bar:", "亮度与对比度调整", &contrast_value, contrast_max, on_contrast, (void*)(&image));
}

test440.cpp

#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>
using namespace cv;
using namespace std;
int main(int argc, char**argv) {
  // imread函数的第二个参数有很多,默认为IMREAD_COLOR,还有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,实现对不同图片的读取操作
  // B,G,R
  Mat src = imread("D:/images/dark_face.jpg");   //Mat为matrix,二维图像都是Mat类型,第一个参数为图片绝对路径
  if (src.empty()) {
    printf("could not load image...\n");
    return -1;
  }
  //namedWindow("输入窗口", WINDOW_FREERATIO);   //不管图片大小,都能进行调整,图像很小可以不使用这个函数
  imshow("输入窗口", src);                    //第一个参数为窗口名
  QuickDemo qd;
  qd.tracking_bar_demo(src);
  waitKey(0);                               //窗口停留时间,0为一直停留,数值为停留的毫秒数
  destroyAllWindows();                      //关闭所有打开的窗口
  return 0;
}

效果

image.png

2.8、滚动条操作-键盘响应操作

quickopencv.h

#pragma once
#include<opencv2/opencv.hpp>
using namespace cv;
class QuickDemo
{
  public:
    void colorSpace_Demo(Mat &image);
    void mat_creation_demo();
    void pixel_visit_demo(Mat &image);
    void operators_demo(Mat &image);
    void tracking_bar_demo(Mat &image);
    void key_demo(Mat &image);
};

quickdemo.cpp

void QuickDemo::key_demo(Mat &image) {
  Mat dst = Mat::zeros(image.size(), image.type());
  while (true) 
  {
    int c = waitKey(1); //waitKey(图像刷新时间间隔)不断刷新图像,刷新间隔时间为1ms,视频处理时尽量设置1ms
    if (c == 27) { // 退出
      break;
    }
    if (c == 49) { // Key #1
      cvtColor(image, dst, COLOR_BGR2GRAY);
      imshow("键盘响应01", dst);
    }
    if (c == 50) { // Key #2
      cvtColor(image, dst, COLOR_BGR2HSV);
      imshow("键盘响应02", dst);
    }
    if (c == 51) { // Key #3
      dst = Scalar(50, 50, 50);
      add(image, dst, dst);
      imshow("键盘响应03", dst);
    }
    //imshow("键盘响应", dst);
  }
}

test440.cpp

#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>
using namespace cv;
using namespace std;
int main(int argc, char**argv) {
  // imread函数的第二个参数有很多,默认为IMREAD_COLOR,还有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,实现对不同图片的读取操作
  // B,G,R
  Mat src = imread("D:/images/lena.jpg");   //Mat为matrix,二维图像都是Mat类型,第一个参数为图片绝对路径
  if (src.empty()) {
    printf("could not load image...\n");
    return -1;
  }
  //namedWindow("输入窗口", WINDOW_FREERATIO);   //不管图片大小,都能进行调整,图像很小可以不使用这个函数
  imshow("输入窗口", src);                    //第一个参数为窗口名
  QuickDemo qd;
  qd.key_demo(src);
  waitKey(0);                               //窗口停留时间,0为一直停留,数值为停留的毫秒数
  destroyAllWindows();                      //关闭所有打开的窗口
  return 0;
}

效果

image.png

2.9、OpenCV自带颜色表操作

quickopencv.h

#pragma once
#include<opencv2/opencv.hpp>
using namespace cv;
class QuickDemo {
  public:
    void colorSpace_Demo(Mat &image);
    void mat_creation_demo();
    void pixel_visit_demo(Mat &image);
    void operators_demo(Mat &image);
    void tracking_bar_demo(Mat &image);
    void key_demo(Mat &image);
    void color_style_demo(Mat &image);
};

quickdemo.cpp

void QuickDemo::color_style_demo(Mat &image) {
  int colormap[] = {
    COLORMAP_AUTUMN,
    COLORMAP_BONE,
    COLORMAP_JET,
    COLORMAP_WINTER,
    COLORMAP_RAINBOW,
    COLORMAP_OCEAN,
    COLORMAP_SUMMER,
    COLORMAP_SPRING,
    COLORMAP_COOL,
    COLORMAP_PINK,
    COLORMAP_HOT,
    COLORMAP_PARULA,
    COLORMAP_MAGMA,
    COLORMAP_INFERNO,
    COLORMAP_PLASMA,
    COLORMAP_VIRIDIS,
    COLORMAP_CIVIDIS,
    COLORMAP_TWILIGHT,
    COLORMAP_TWILIGHT_SHIFTED
  };
  Mat dst;
  int index = 0;
  while (true) {
    int c = waitKey(2000);
    if (c == 27) {
      break;
    }
    applyColorMap(image, dst, colormap[index%19]);
    index++;
    imshow("颜色风格", dst);
  }
}

test440.cpp

#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>
using namespace cv;
using namespace std;
int main(int argc, char**argv) {
  // imread函数的第二个参数有很多,默认为IMREAD_COLOR,还有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,实现对不同图片的读取操作
  // B,G,R
  Mat src = imread("D:/images/lena.jpg");   //Mat为matrix,二维图像都是Mat类型,第一个参数为图片绝对路径
  if (src.empty()) {
    printf("could not load image...\n");
    return -1;
  }
  //namedWindow("输入窗口", WINDOW_FREERATIO);   //不管图片大小,都能进行调整,图像很小可以不使用这个函数
  imshow("输入窗口", src);                    //第一个参数为窗口名
  QuickDemo qd;
  qd.color_style_demo(src);
  waitKey(0);                               //窗口停留时间,0为一直停留,数值为停留的毫秒数
  destroyAllWindows();                      //关闭所有打开的窗口
  return 0;
}

效果

image.png

2.10、图像像素的逻辑操作

quickopencv.h

#pragma once
#include<opencv2/opencv.hpp>
using namespace cv;
class QuickDemo {
    public:
        void colorSpace_Demo(Mat &image);
        void mat_creation_demo();
        void pixel_visit_demo(Mat &image);
        void operators_demo(Mat &image);
        void tracking_bar_demo(Mat &image);
        void key_demo(Mat &image);
        void color_style_demo(Mat &image);
        void bitwise_demo(Mat &image);
};

quickdemo.cpp

void QuickDemo::bitwise_demo(Mat &image) {
    Mat m1 = Mat::zeros(Size(256, 256), CV_8UC3);
    Mat m2 = Mat::zeros(Size(256, 256), CV_8UC3);
    //rectangle()函数第四个参数小于0表示填充,大于0表示绘制
    //rectangle(m1, Rect(100, 100, 80, 80), Scalar(255, 255, 0), 2, LINE_8, 0);
    //rectangle(m2, Rect(150, 150, 80, 80), Scalar(0, 255, 255), 2, LINE_8, 0);
    rectangle(m1, Rect(100, 100, 80, 80), Scalar(255, 255, 0), -1, LINE_8, 0);
    rectangle(m2, Rect(150, 150, 80, 80), Scalar(0, 255, 255), -1, LINE_8, 0);
    imshow("m1", m1);
    imshow("m2", m2);
    Mat dst;
    //bitwise_and(m1, m2, dst);
    //bitwise_or(m1, m2, dst);
    //dst = ~image;  //也可以实现图像取反操作
    //bitwise_not(image, dst);  //当前图像取反操作
    bitwise_xor(m1, m2, dst);  //异或((非m1 与 m2) 或 (m1 与 非m2)),相当于 m1或m2,相交的部分(非(m1 与 m2))
    imshow("像素位操作", dst);
}

test440.cpp

#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>
using namespace cv;
using namespace std;
int main(int argc, char**argv) {
    // imread函数的第二个参数有很多,默认为IMREAD_COLOR,还有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,实现对不同图片的读取操作
    // B,G,R
    Mat src = imread("D:/images/lena.jpg");   //Mat为matrix,二维图像都是Mat类型,第一个参数为图片绝对路径
    if (src.empty()) {
        printf("could not load image...\n");
        return -1;
    }
    //namedWindow("输入窗口", WINDOW_FREERATIO);   //不管图片大小,都能进行调整,图像很小可以不使用这个函数
    imshow("输入窗口", src);                    //第一个参数为窗口名
    QuickDemo qd;
    qd.bitwise_demo(src);
    waitKey(0);                               //窗口停留时间,0为一直停留,数值为停留的毫秒数
    destroyAllWindows();                      //关闭所有打开的窗口
    return 0;
}

效果

image.png

2.11、通道分离与合并

quickopencv.h

#pragma once
#include<opencv2/opencv.hpp>
using namespace cv;
class QuickDemo {
    public:
        void colorSpace_Demo(Mat &image);
        void mat_creation_demo();
        void pixel_visit_demo(Mat &image);
        void operators_demo(Mat &image);
        void tracking_bar_demo(Mat &image);
        void key_demo(Mat &image);
        void color_style_demo(Mat &image);
        void bitwise_demo(Mat &image);
        void channels_demo(Mat &image);
};

quickdemo.cpp

void QuickDemo::channels_demo(Mat &image) {
    std::vector<Mat> mv;  //Mat数组
    split(image, mv);
    imshow("蓝色", mv[0]);
    imshow("绿色", mv[1]);
    imshow("红色", mv[2]);
    Mat dst;
    //mv[1] = 0;
    //mv[2] = 0;
    //merge(mv, dst);
    //imshow("蓝色", dst);
    //mv[0] = 0;
    //mv[2] = 0;
    //merge(mv, dst);
    //imshow("绿色", dst);
    mv[0] = 0;
    mv[1] = 0;
    merge(mv, dst);
    imshow("红色", dst);
    //from_to[]复制列表
    int from_to[] = { 0,2,1,1,2,0 };  //通道0复制到通道2,通道1复制到通道1,通道2复制到通道0
    //mixChannels(输入矩阵,输入矩阵数量,输出矩阵,输出矩阵数量,复制列表,复制列表中复制几次)
    mixChannels(&image, 1, &dst, 1, from_to, 3);
    imshow("通道混合", dst);
}

test440.cpp

#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>
using namespace cv;
using namespace std;
int main(int argc, char**argv) {
    // imread函数的第二个参数有很多,默认为IMREAD_COLOR,还有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,实现对不同图片的读取操作
    // B,G,R
    Mat src = imread("D:/images/flower.jpg");   //Mat为matrix,二维图像都是Mat类型,第一个参数为图片绝对路径
    if (src.empty()) {
        printf("could not load image...\n");
        return -1;
    }
    //namedWindow("输入窗口", WINDOW_FREERATIO);   //不管图片大小,都能进行调整,图像很小可以不使用这个函数
    imshow("输入窗口", src);                    //第一个参数为窗口名
    QuickDemo qd;
    qd.channels_demo(src);
    waitKey(0);                               //窗口停留时间,0为一直停留,数值为停留的毫秒数
    destroyAllWindows();                      //关闭所有打开的窗口
    return 0;
}

效果

image.png

2.12、图像色彩空间转换

HSV颜色空间表

image.png

quickopencv.h

#pragma once
#include<opencv2/opencv.hpp>
using namespace cv;
class QuickDemo {
    public:
        void colorSpace_Demo(Mat &image);
        void mat_creation_demo();
        void pixel_visit_demo(Mat &image);
        void operators_demo(Mat &image);
        void tracking_bar_demo(Mat &image);
        void key_demo(Mat &image);
        void color_style_demo(Mat &image);
        void bitwise_demo(Mat &image);
        void channels_demo(Mat &image);
        void inrange_demo(Mat &image);
};

quickdemo.cpp

void QuickDemo::inrange_demo(Mat &image) {
    Mat hsv;
    cvtColor(image, hsv, COLOR_BGR2HSV);
    Mat mask;
    inRange(hsv, Scalar(35, 43, 46), Scalar(77, 255, 255), mask);
    imshow("mask01", mask);
    Mat redback = Mat::zeros(image.size(), image.type());
    redback = Scalar(40, 40, 200);
    bitwise_not(mask, mask);  //像素逻辑运算,mask取反
    imshow("mask02", mask);
    //image.copyTo(拷贝到的图像,mask为1的部分拷贝为0的部分不拷贝)
    image.copyTo(redback, mask);  //将image拷贝到其他图像中
    imshow("roi区域提取", redback);
}

test440.cpp

#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>
using namespace cv;
using namespace std;
int main(int argc, char**argv) {
    // imread函数的第二个参数有很多,默认为IMREAD_COLOR,还有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,实现对不同图片的读取操作
    // B,G,R
    Mat src = imread("D:/images/greenback.jpg");   //Mat为matrix,二维图像都是Mat类型,第一个参数为图片绝对路径
    if (src.empty()) {
        printf("could not load image...\n");
        return -1;
    }
    //namedWindow("输入窗口", WINDOW_FREERATIO);   //不管图片大小,都能进行调整,图像很小可以不使用这个函数
    imshow("输入窗口", src);                    //第一个参数为窗口名
    QuickDemo qd;
    qd.inrange_demo(src);
    waitKey(0);                               //窗口停留时间,0为一直停留,数值为停留的毫秒数
    destroyAllWindows();                      //关闭所有打开的窗口
    return 0;
}

效果

image.png

2.13、图像像素值统计

quickopencv.h

#pragma once
#include<opencv2/opencv.hpp>
using namespace cv;
class QuickDemo {
    public:
        void colorSpace_Demo(Mat &image);
        void mat_creation_demo();
        void pixel_visit_demo(Mat &image);
        void operators_demo(Mat &image);
        void tracking_bar_demo(Mat &image);
        void key_demo(Mat &image);
        void color_style_demo(Mat &image);
        void bitwise_demo(Mat &image);
        void channels_demo(Mat &image);
        void inrange_demo(Mat &image);
                void pixel_statistic_demo(Mat &image);
};

quickdemo.cpp

void QuickDemo::pixel_statistic_demo(Mat &image) {
    double minv, maxv;
    Point minLoc, maxLoc;
    Mat mean, stddev;
    std::vector<Mat> mv;
    split(image, mv);
    for (int i = 0; i < mv.size(); i++) {
        //第一个参数需要是单通道的图像,可以先把多通道分离;最后一个参数为mask
        minMaxLoc(mv[i], &minv, &maxv, &minLoc, &maxLoc, Mat());
        std::cout << "No.channels: " << i << " min value: " << minv << " max value: " << maxv << std::endl;
        //第一个参数是单通道图像则计算一组均值、方差,如果是多通道图像,则同时计算多组均值、方差
        meanStdDev(mv[i], mean, stddev);
        std::cout << "means: " << mean << std::endl;
        std::cout << "stddev: " << stddev << std::endl;
    }
}

test440.cpp

#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>
using namespace cv;
using namespace std;
int main(int argc, char**argv) {
    // imread函数的第二个参数有很多,默认为IMREAD_COLOR,还有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,实现对不同图片的读取操作
    // B,G,R
    Mat src = imread("D:/images/greenback.jpg");   //Mat为matrix,二维图像都是Mat类型,第一个参数为图片绝对路径
    if (src.empty()) {
        printf("could not load image...\n");
        return -1;
    }
    //namedWindow("输入窗口", WINDOW_FREERATIO);   //不管图片大小,都能进行调整,图像很小可以不使用这个函数
    imshow("输入窗口", src);                    //第一个参数为窗口名
    QuickDemo qd;
    qd.pixel_statistic_demo(src);
    waitKey(0);                               //窗口停留时间,0为一直停留,数值为停留的毫秒数
    destroyAllWindows();                      //关闭所有打开的窗口
    return 0;
}

效果

image.png

2.14、图像几何形状绘制,随机数与随机颜色

基本绘图

1 Point:
 2     Point pt;
 3     pt.x = 10;
 4     pt.y = 8;
 5     或者
 6     Point pt =  Point(10, 8);
 7  
 8 Scalar:
 9     Scalar( B, G, R )   //定义的RGB颜色值为:Blue,Green, Red
10     
11 line 绘直线:
12     line( img,   //输出图像
13         start,   //起始点
14         end,     //结束点
15         Scalar( 0, 0, 0 ),  //颜色
16         thickness=2,    //线条粗细
17         lineType=8 );   //线条类型
18  
19 ellipse 绘椭圆:
20     ellipse( img,   //输出图像
21            Point( w/2.0, w/2.0 ),   //中心为点 (w/2.0, w/2.0) 
22            Size( w/4.0, w/16.0 ),     //大小位于矩形 (w/4.0, w/16.0) 内
23            angle,    //旋转角度为 angle
24            0,
25            360,     //扩展的弧度从 0 度到 360 度
26            Scalar( 255, 0, 0 ),   //颜色
27            thickness,   //线条粗细
28            lineType );    //线条类型
29  
30 circle 绘圆:
31     circle( img,   //输出图像
32          center,    //圆心由点 center 定义
33          w/32.0,     /圆的半径为: w/32.0
34          Scalar( 0, 0, 255 ),   //颜色
35          thickness,   //线条粗细
36          lineType );   //线条类型
37          
38 rectangle 绘矩形:
39     rectangle( rook_image,
40            Point( 0, 7*w/8.0 ),
41            Point( w, w),    //矩形两个对角顶点为 Point( 0, 7*w/8.0 ) 和 Point( w, w)
42            Scalar( 0, 255, 255 ),
43            thickness = -1,
44            lineType = 8 );
45  
46 fillPoly 绘填充的多边形:
47     fillPoly( img,
48             ppt,   //多边形的顶点集为 ppt
49             npt,   //要绘制的多边形顶点数目为 npt
50             1,   //要绘制的多边形数量仅为 1
51             Scalar( 255, 255, 255 ),
52             lineType );

quickopencv.h

#pragma once
#include<opencv2/opencv.hpp>
using namespace cv;
class QuickDemo {
    public:
        void colorSpace_Demo(Mat &image);
        void mat_creation_demo();
        void pixel_visit_demo(Mat &image);
        void operators_demo(Mat &image);
        void tracking_bar_demo(Mat &image);
        void key_demo(Mat &image);
        void color_style_demo(Mat &image);
        void bitwise_demo(Mat &image);
        void channels_demo(Mat &image);
        void inrange_demo(Mat &image);
                void pixel_statistic_demo(Mat &image);
                void form_paint_random();
};

quickdemo.cpp

void QuickDemo::form_paint_random() {
    Mat image_line = Mat::zeros(512, 512, CV_8UC3);  //新建两个512*512的三通道矩阵
    Mat image_rect = Mat::zeros(512, 512, CV_8UC3);
    Rect rect;  //新建一个矩形对象
    RNG rng(0xFFFFFF);  //生成随机数的类RNG,随机数产生器,用数值0xFFFFFF来实例化一个RNG对象
    image_line.setTo(Scalar(0, 0, 0));  //将图像使用另一种颜色覆盖
    image_rect.setTo(Scalar(0, 0, 0));  //将图像使用另一种颜色覆盖
    for (int i = 0; i < 100000; i++) {
        int x1 = rng.uniform(0, 512);  //获取[0,512)的均匀分布的随机数
        int y1 = rng.uniform(0, 512);
        int x2 = rng.uniform(0, 512);
        int y2 = rng.uniform(0, 512);
        int b = rng.uniform(0, 256);
        int g = rng.uniform(0, 256);
        int r = rng.uniform(0, 256);
        //void line(绘制线段的图像,起点坐标,终点坐标,线段的颜色通过Scalar()定义,线段的宽度(线宽为负数时表示填充),线段的类型,坐标点小数点位数)
        line(image_line, Point(x1, y1), Point(x2, y2), Scalar(b, g, r), 1, LINE_AA, 0);  //线段的类型。可以取值LINE_8,LINE_4和LINE_AA,分别代表8邻接连接线,4邻接连接线和反锯齿连接线。默认值为8邻接。为了获得更好地效果可以选用LINE_AA(采用了高斯滤波)。
        imshow("image_line", image_line);
        rect.x = x1;  //定义矩形的左上顶点坐标及宽高
        rect.y = y1;
        rect.width = x2 - x1;
        rect.height = y2 - y1;
        rectangle(image_rect, rect, Scalar(b, g, r), 1, LINE_AA, 0);
        imshow("image_rect", image_rect);
        char c = waitKey(20);
        if (c == 27)
            break;
    }
}

test440.cpp

#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>
using namespace cv;
using namespace std;
int main(int argc, char**argv) {
    // imread函数的第二个参数有很多,默认为IMREAD_COLOR,还有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,实现对不同图片的读取操作
    // B,G,R
    Mat src = imread("D:/images/greenback.jpg");   //Mat为matrix,二维图像都是Mat类型,第一个参数为图片绝对路径
    if (src.empty()) {
        printf("could not load image...\n");
        return -1;
    }
    //namedWindow("输入窗口", WINDOW_FREERATIO);   //不管图片大小,都能进行调整,图像很小可以不使用这个函数
    //imshow("输入窗口", src);                    //第一个参数为窗口名
    QuickDemo qd;
    qd.form_paint_random();
    waitKey(0);                               //窗口停留时间,0为一直停留,数值为停留的毫秒数
    destroyAllWindows();                      //关闭所有打开的窗口
    return 0;
}

效果

image.png

2.15、多边形填充与绘制

quickopencv.h

#pragma once
#include<opencv2/opencv.hpp>
using namespace cv;
class QuickDemo {
    public:
        void colorSpace_Demo(Mat &image);
        void mat_creation_demo();
        void pixel_visit_demo(Mat &image);
        void operators_demo(Mat &image);
        void tracking_bar_demo(Mat &image);
        void key_demo(Mat &image);
        void color_style_demo(Mat &image);
        void bitwise_demo(Mat &image);
        void channels_demo(Mat &image);
        void inrange_demo(Mat &image);
                void pixel_statistic_demo(Mat &image);
                void form_paint_random();
                void polyline_drawing_demo();
};

quickdemo.cpp

void QuickDemo::polyline_drawing_demo() {
    Mat canvas01 = Mat::zeros(Size(512, 512), CV_8UC3);
    Mat canvas02 = Mat::zeros(Size(512, 512), CV_8UC3);
    Point p1(100, 100);
    Point p2(350, 100);
    Point p3(450, 280);
    Point p4(320, 450);
    Point p5(80, 400);
    std::vector<Point> pts;
    pts.push_back(p1);
    pts.push_back(p2);
    pts.push_back(p3);
    pts.push_back(p4);
    pts.push_back(p5);
    fillPoly(canvas01, pts, Scalar(255, 255, 0), 8, 0);
    //polylines(绘制所在图像,要绘制的顶点集合,图形是否闭合,线的颜色,线宽,线的类型)
    //polylines(canvas, pts, true, Scalar(0, 0, 255), 3, LINE_8, 0);  //不能设置线宽为负数进行填充
    polylines(canvas01, pts, true, Scalar(0, 0, 255), 3, LINE_AA, 0);  //使用LINE_AA抗锯齿
    std::vector<std::vector<Point>> contours;
    contours.push_back(pts);
    //drawContours(绘制所在的图像,绘制的点集的集合,绘制第几个点集-1表示全部绘制,线段颜色,线宽-1表示填充)
    drawContours(canvas02, contours, -1, Scalar(255, 0, 0), -1);
    imshow("多边形绘制01", canvas01);
    imshow("多边形绘制02", canvas02);
}

test440.cpp

#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>
using namespace cv;
using namespace std;
int main(int argc, char**argv) {
    // imread函数的第二个参数有很多,默认为IMREAD_COLOR,还有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,实现对不同图片的读取操作
    // B,G,R
    Mat src = imread("D:/images/greenback.jpg");   //Mat为matrix,二维图像都是Mat类型,第一个参数为图片绝对路径
    if (src.empty()) {
        printf("could not load image...\n");
        return -1;
    }
    //namedWindow("输入窗口", WINDOW_FREERATIO);   //不管图片大小,都能进行调整,图像很小可以不使用这个函数
    //imshow("输入窗口", src);                    //第一个参数为窗口名
    QuickDemo qd;
    qd.polyline_drawing_demo();
    waitKey(0);                               //窗口停留时间,0为一直停留,数值为停留的毫秒数
    destroyAllWindows();                      //关闭所有打开的窗口
    return 0;
}

效果

image.png

2.16、鼠标操作与响应

quickopencv.h

#pragma once
#include<opencv2/opencv.hpp>
using namespace cv;
class QuickDemo {
    public:
        void colorSpace_Demo(Mat &image);
        void mat_creation_demo();
        void pixel_visit_demo(Mat &image);
        void operators_demo(Mat &image);
        void tracking_bar_demo(Mat &image);
        void key_demo(Mat &image);
        void color_style_demo(Mat &image);
        void bitwise_demo(Mat &image);
        void channels_demo(Mat &image);
        void inrange_demo(Mat &image);
                void pixel_statistic_demo(Mat &image);
                void form_paint_random();
                void polyline_drawing_demo();
        void mouse_drawing_demo(Mat &image);
};

quickdemo.cpp

Point sp(-1, -1);  //起点
Point ep(-1, -1);  //终点
//新建一个temp矩阵保存原图像,没有绘制的
Mat temp;
static void on_draw(int event, int x, int y, int flags, void *userdata) {
    Mat image = *((Mat*)userdata);
    if (event == EVENT_LBUTTONDOWN) {
        sp.x = x;
        sp.y = y;
        std::cout << "start point: " << sp << std::endl;
    }
    else if (event == EVENT_LBUTTONUP) {
        ep.x = x;
        ep.y = y;
        int dx = ep.x - sp.x;
        int dy = ep.y - sp.y;
        if (dx > 0 && dy > 0) {
            Rect box(sp.x, sp.y, dx, dy);
            temp.copyTo(image);  //去除绘制目标区域的边框
            imshow("ROI区域", image(box));  //将绘制区域中的图像单独显示出来
            rectangle(image, box, Scalar(0, 0, 255), 2, 8, 0);
            imshow("鼠标绘制", image);
            //ready for next drawing
            sp.x = -1;
            sp.y = -1;
        }
    }
    else if (event == EVENT_MOUSEMOVE) {
        if (sp.x > 0 && sp.y > 0) {
            ep.x = x;
            ep.y = y;
            int dx = ep.x - sp.x;
            int dy = ep.y - sp.y;
            if (dx > 0 && dy > 0) {
                Rect box(sp.x, sp.y, dx, dy);
                temp.copyTo(image);  //每次都重新加载没有绘制的原图,实现擦除过程中绘制的图形
                rectangle(image, box, Scalar(0, 0, 255), 2, 8, 0);
                imshow("鼠标绘制", image);
            }
        }
    }
}
void QuickDemo::mouse_drawing_demo(Mat &image) {
    namedWindow("鼠标绘制", WINDOW_AUTOSIZE);
    setMouseCallback("鼠标绘制", on_draw, (void*)(&image));
    imshow("鼠标绘制", image);
    temp = image.clone();  //将加载的原图克隆到临时矩阵temp中
}

test440.cpp

#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>
using namespace cv;
using namespace std;
int main(int argc, char**argv) {
    // imread函数的第二个参数有很多,默认为IMREAD_COLOR,还有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,实现对不同图片的读取操作
    // B,G,R
    Mat src = imread("D:/images/greenback.jpg");   //Mat为matrix,二维图像都是Mat类型,第一个参数为图片绝对路径
    if (src.empty()) {
        printf("could not load image...\n");
        return -1;
    }
    //namedWindow("输入窗口", WINDOW_FREERATIO);   //不管图片大小,都能进行调整,图像很小可以不使用这个函数
    //imshow("输入窗口", src);                    //第一个参数为窗口名
    QuickDemo qd;
    qd.mouse_drawing_demo(src);
    waitKey(0);                               //窗口停留时间,0为一直停留,数值为停留的毫秒数
    destroyAllWindows();                      //关闭所有打开的窗口
    return 0;
}

效果

image.png

2.17、图像像素类型转换与归一化

图像为什么要进行归一化:

归一化就是要把需要处理的数据经过处理后(通过某种算法)限制在你需要的一定范围内。首先归一化是为了后面数据处理的方便,其次是保证程序运行时收敛加快。归一化的具体作用是归纳统一样本的统计分布性。归一化在0-1之间是统计的概率分布,归一化在某个区间上是统计的坐标分布。归一化有同一、统一和合一的意思。

归一化的目的简而言之,是使得没有可比性的数据变得具有可比性,同时又保持相比较的两个数据之间的相对关系,如大小关系;或是为了作图,原来很难在一张图上作出来,归一化后就可以很方便的给出图上的相对位置等。

四种归一化方式:

其中的NORM_L2计算方式实例如下公式,其他归一化方式根据图片中的内容即可理解

2.0÷22+82+102−−−−−−−−−−−√≈0.152.0÷22+82+102≈0.15

image.png

quickopencv.h

#pragma once
#include<opencv2/opencv.hpp>
using namespace cv;
class QuickDemo {
    public:
        void colorSpace_Demo(Mat &image);
        void mat_creation_demo();
        void pixel_visit_demo(Mat &image);
        void operators_demo(Mat &image);
        void tracking_bar_demo(Mat &image);
        void key_demo(Mat &image);
        void color_style_demo(Mat &image);
        void bitwise_demo(Mat &image);
        void channels_demo(Mat &image);
        void inrange_demo(Mat &image);
                void pixel_statistic_demo(Mat &image);
                void form_paint_random();
                void polyline_drawing_demo();
        void mouse_drawing_demo(Mat &image);
                void norm_demo(Mat &image);
};

quickdemo.cpp

//image.type()返回的数值与类型对应关系,第一行为通道数,第一列为数据类型
+--------+----+----+----+----+------+------+------+------+
|        | C1 | C2 | C3 | C4 | C(5) | C(6) | C(7) | C(8) |
+--------+----+----+----+----+------+------+------+------+
| CV_8U  |  0 |  8 | 16 | 24 |   32 |   40 |   48 |   56 |
| CV_8S  |  1 |  9 | 17 | 25 |   33 |   41 |   49 |   57 |
| CV_16U |  2 | 10 | 18 | 26 |   34 |   42 |   50 |   58 |
| CV_16S |  3 | 11 | 19 | 27 |   35 |   43 |   51 |   59 |
| CV_32S |  4 | 12 | 20 | 28 |   36 |   44 |   52 |   60 |
| CV_32F |  5 | 13 | 21 | 29 |   37 |   45 |   53 |   61 |
| CV_64F |  6 | 14 | 22 | 30 |   38 |   46 |   54 |   62 |
+--------+----+----+----+----+------+------+------+------+
void QuickDemo::norm_demo(Mat &image) {
    Mat dst;
    std::cout << image.type() << std::endl;
    image.convertTo(image, CV_32F);  //将8UC3 Integer数据转换成32F float数据,以便用于后续归一化操作
    std::cout << image.type() << std::endl;
    //值归一化与范围归一化:值归一化L1,L2,MINMAX;范围归一化可以自己设置归一化范围如[0,255]
    //normalize(输入数组,输出数组,1用来规范值2规范范围下限,0值归一化其他范围归一化上限,归一化选择的数学公式类型)
    normalize(image, dst, 1.0, 0, NORM_MINMAX);  //转换为浮点数类型后必须进行归一化操作
    std::cout << dst.type() << std::endl;
    imshow("图像数据归一化前", image);
    imshow("图像数据归一化后", dst);
    //CV_8UC3, CV_32FC3
}

test440.cpp

#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>
using namespace cv;
using namespace std;
int main(int argc, char**argv) {
    // imread函数的第二个参数有很多,默认为IMREAD_COLOR,还有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,实现对不同图片的读取操作
    // B,G,R
    Mat src = imread("D:/images/greenback.jpg");   //Mat为matrix,二维图像都是Mat类型,第一个参数为图片绝对路径
    if (src.empty()) {
        printf("could not load image...\n");
        return -1;
    }
    //namedWindow("输入窗口", WINDOW_FREERATIO);   //不管图片大小,都能进行调整,图像很小可以不使用这个函数
    imshow("输入窗口", src);                    //第一个参数为窗口名
    QuickDemo qd;
    qd.norm_demo(src);
    waitKey(0);                               //窗口停留时间,0为一直停留,数值为停留的毫秒数
    destroyAllWindows();                      //关闭所有打开的窗口
    return 0;
}

效果

image.png

2.18、图像放缩与插值

OpenCV图像放缩的五种插值算法:最近邻、双线性、双三次、基于像素区域关系、兰索斯插值。

1、最近邻:选取离目标点最近的点作为新的插入点;

2、双线性:由相邻的四像素(2 * 2)计算得出;

  • 原理公式及矩阵

image.png

  • 计算过程示意图

image.png

3、双三次:由相邻的4 * 4像素计算得出,公式类似于双线性插值;

4、基于像素区域关系:共分三种情况,图像放大时类似于双线性插值,图像缩小(x轴、y轴同时缩小)又分两种情况,此情况下可以避免波纹出现;

5、兰索斯插值:由相邻的8 * 8像素计算得出,公式类似于双线性

总结:

  • 速度比较:INTER_NEAREST(最近邻插值)>INTER_LINEAR(双线性插值)>INTER_CUBIC(三次样条插值)>INTER_AREA(区域插值)

  • OpenCV推荐:如果要缩小图像,通常推荐使用 INTER_AREA插值效果最好;而要放大图像,通常使用 INTER_CUBIC(速度较慢,但效果最好),或者使用 INTER_LINEAR(速度较快,效果还可以)。至于最近邻插值 INTER_NEAREST,一般不推荐使用

quickopencv.h

#pragma once
#include<opencv2/opencv.hpp>
using namespace cv;
class QuickDemo {
    public:
        void colorSpace_Demo(Mat &image);
        void mat_creation_demo();
        void pixel_visit_demo(Mat &image);
        void operators_demo(Mat &image);
        void tracking_bar_demo(Mat &image);
        void key_demo(Mat &image);
        void color_style_demo(Mat &image);
        void bitwise_demo(Mat &image);
        void channels_demo(Mat &image);
        void inrange_demo(Mat &image);
                void pixel_statistic_demo(Mat &image);
                void form_paint_random();
                void polyline_drawing_demo();
        void mouse_drawing_demo(Mat &image);
                void norm_demo(Mat &image);
                void resize_demo(Mat &image);
};

quickdemo.cpp

void QuickDemo::resize_demo(Mat &image) {
    Mat zoomin, zoomout;
    int h = image.rows;
    int w = image.cols;
    //resize(输入图像,输出图像,大小变换方法Size(),x方向缩放系数,y方向缩放系数,插值算法)
    //如果size有值,使用size做放缩插值,否则根据fx与fy卷积
    resize(image, zoomin, Size(w / 2, h / 2), 0, 0, INTER_LINEAR);
    imshow("zoomin", zoomin);
    resize(image, zoomout, Size(w * 1.5, h * 1.5), 0, 0, INTER_LINEAR);
    imshow("zoomout", zoomout);
}

test440.cpp

#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>
using namespace cv;
using namespace std;
int main(int argc, char**argv) {
    // imread函数的第二个参数有很多,默认为IMREAD_COLOR,还有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,实现对不同图片的读取操作
    // B,G,R
    Mat src = imread("D:/images/greenback.jpg");   //Mat为matrix,二维图像都是Mat类型,第一个参数为图片绝对路径
    if (src.empty()) {
        printf("could not load image...\n");
        return -1;
    }
    //namedWindow("输入窗口", WINDOW_FREERATIO);   //不管图片大小,都能进行调整,图像很小可以不使用这个函数
    imshow("输入窗口", src);                    //第一个参数为窗口名
    QuickDemo qd;
    qd.resize_demo(src);
    waitKey(0);                               //窗口停留时间,0为一直停留,数值为停留的毫秒数
    destroyAllWindows();                      //关闭所有打开的窗口
    return 0;
}

效果

image.png

2.19、图像翻转

quickopencv.h

#pragma once
#include<opencv2/opencv.hpp>
using namespace cv;
class QuickDemo {
    public:
        void colorSpace_Demo(Mat &image);
        void mat_creation_demo();
        void pixel_visit_demo(Mat &image);
        void operators_demo(Mat &image);
        void tracking_bar_demo(Mat &image);
        void key_demo(Mat &image);
        void color_style_demo(Mat &image);
        void bitwise_demo(Mat &image);
        void channels_demo(Mat &image);
        void inrange_demo(Mat &image);
                void pixel_statistic_demo(Mat &image);
                void form_paint_random();
                void polyline_drawing_demo();
        void mouse_drawing_demo(Mat &image);
                void norm_demo(Mat &image);
                void resize_demo(Mat &image);
                void flip_demo(Mat &image);
};

quickdemo.cpp

void QuickDemo::flip_demo(Mat &image) {
    Mat dst;
    flip(image, dst, 0);  //上下翻转
    imshow("图像上下翻转", dst);
    flip(image, dst, 1);  //左右翻转
    imshow("图像左右翻转", dst);
    flip(image, dst, -1);  //180°旋转
    imshow("图像180°翻转", dst);
}

test440.cpp

#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>
using namespace cv;
using namespace std;
int main(int argc, char**argv) {
    // imread函数的第二个参数有很多,默认为IMREAD_COLOR,还有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,实现对不同图片的读取操作
    // B,G,R
    Mat src = imread("D:/images/greenback.jpg");   //Mat为matrix,二维图像都是Mat类型,第一个参数为图片绝对路径
    if (src.empty()) {
        printf("could not load image...\n");
        return -1;
    }
    //namedWindow("输入窗口", WINDOW_FREERATIO);   //不管图片大小,都能进行调整,图像很小可以不使用这个函数
    imshow("输入窗口", src);                    //第一个参数为窗口名
    QuickDemo qd;
    qd.flip_demo(src);
    waitKey(0);                               //窗口停留时间,0为一直停留,数值为停留的毫秒数
    destroyAllWindows();                      //关闭所有打开的窗口
    return 0;
}

效果

image.png

2.20、图像旋转

公式:

\[i′=icosθ−jsinθi′=icosθ−jsin⁡θ \]

\[i′=isinθ+jcosθi′=isin⁡θ+jcosθ \]

quickopencv.h

#pragma once
#include<opencv2/opencv.hpp>
using namespace cv;
class QuickDemo {
    public:
        void colorSpace_Demo(Mat &image);
        void mat_creation_demo();
        void pixel_visit_demo(Mat &image);
        void operators_demo(Mat &image);
        void tracking_bar_demo(Mat &image);
        void key_demo(Mat &image);
        void color_style_demo(Mat &image);
        void bitwise_demo(Mat &image);
        void channels_demo(Mat &image);
        void inrange_demo(Mat &image);
                void pixel_statistic_demo(Mat &image);
                void form_paint_random();
                void polyline_drawing_demo();
        void mouse_drawing_demo(Mat &image);
                void norm_demo(Mat &image);
                void resize_demo(Mat &image);
                void flip_demo(Mat &image);
                void rotate_demo(Mat &image);
};

quickdemo.cpp

void QuickDemo::rotate_demo(Mat &image) {
    Mat dst, M;
    int w = image.cols;
    int h = image.rows;
    M = getRotationMatrix2D(Point2f(w / 2, h / 2), 45, 1.0);
    double cos = abs(M.at<double>(0, 0));
    double sin = abs(M.at<double>(0, 1));
    int nw = cos * w + sin * h;
    int nh = sin * w + cos * h;
    M.at<double>(0, 2) += (nw / 2 - w / 2);
    M.at<double>(1, 2) += (nh / 2 - h / 2);
    warpAffine(image, dst, M, Size(nw, nh), INTER_LINEAR, 0, Scalar(255, 255, 0));
    imshow("旋转展示", dst);
}

test440.cpp

#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>
using namespace cv;
using namespace std;
int main(int argc, char**argv) {
    // imread函数的第二个参数有很多,默认为IMREAD_COLOR,还有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,实现对不同图片的读取操作
    // B,G,R
    Mat src = imread("D:/images/lena.jpg");   //Mat为matrix,二维图像都是Mat类型,第一个参数为图片绝对路径
    if (src.empty()) {
        printf("could not load image...\n");
        return -1;
    }
    //namedWindow("输入窗口", WINDOW_FREERATIO);   //不管图片大小,都能进行调整,图像很小可以不使用这个函数
    imshow("输入窗口", src);                    //第一个参数为窗口名
    QuickDemo qd;
    qd.rotate_demo(src);
    waitKey(0);                               //窗口停留时间,0为一直停留,数值为停留的毫秒数
    destroyAllWindows();                      //关闭所有打开的窗口
    return 0;
}

效果

image.png

2.21、视频文件摄像头使用

quickopencv.h

#pragma once
#include<opencv2/opencv.hpp>
using namespace cv;
class QuickDemo {
    public:
        void colorSpace_Demo(Mat &image);
        void mat_creation_demo();
        void pixel_visit_demo(Mat &image);
        void operators_demo(Mat &image);
        void tracking_bar_demo(Mat &image);
        void key_demo(Mat &image);
        void color_style_demo(Mat &image);
        void bitwise_demo(Mat &image);
        void channels_demo(Mat &image);
        void inrange_demo(Mat &image);
                void pixel_statistic_demo(Mat &image);
                void form_paint_random();
                void polyline_drawing_demo();
        void mouse_drawing_demo(Mat &image);
                void norm_demo(Mat &image);
                void resize_demo(Mat &image);
                void flip_demo(Mat &image);
                void rotate_demo(Mat &image);
                void video_demo(Mat &image);
};

quickdemo.cpp

void QuickDemo::video_demo(Mat &image) {
    //VideoCapture capture(0);  //获取当前设备摄像头视频
    VideoCapture capture("D:/images/video/example.mp4");  //获取该地址下的视频
    Mat frame;
    while (true) {
        capture.read(frame);
        int h = frame.rows;  //获取视频每一帧的宽高
        int w = frame.cols;
        //flip(frame, frame, 1);  //摄像头需要翻转,视频不需要翻转
        if (frame.empty()) {
            break;
        }
        resize(frame, frame, Size(w / 4, h / 4), 0, 0, INTER_LINEAR);  //缩放视频
        imshow("frame", frame);  //显示缩放后的视频
        colorSpace_Demo(frame);  //调用色彩空间转换函数,将视频转换为灰度图像及HSV图像并显示
        // TODO: do something....
        int c = waitKey(10);
        if (c == 27) {  //退出
            break;
        }
    }
    
    //release
    capture.release();
}

test440.cpp

#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>
using namespace cv;
using namespace std;
int main(int argc, char**argv) {
    // imread函数的第二个参数有很多,默认为IMREAD_COLOR,还有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,实现对不同图片的读取操作
    // B,G,R
    Mat src = imread("D:/images/lena.jpg");   //Mat为matrix,二维图像都是Mat类型,第一个参数为图片绝对路径
    if (src.empty()) {
        printf("could not load image...\n");
        return -1;
    }
    //namedWindow("输入窗口", WINDOW_FREERATIO);   //不管图片大小,都能进行调整,图像很小可以不使用这个函数
    //imshow("输入窗口", src);                    //第一个参数为窗口名
    QuickDemo qd;
    qd.video_demo(src);
    waitKey(0);                               //窗口停留时间,0为一直停留,数值为停留的毫秒数
    destroyAllWindows();                      //关闭所有打开的窗口
    return 0;
}

效果

image.png

2.22、视频处理与保存

分辨率清晰度对照:

视频显示格式 分辨率尺寸名 汉语简称
480p、576p SD(Standard Definition) 标清
720p HD(High Definition) 高清
1080p FHD(Full High Definition) 全高清
2k QHD(Quad High Definition) 四倍HD
4k UHD(Ultra High Definition) 超高清 或 4k UHD
8k FUHD(Full Ultra High Definition) 8k超高清 或 8k UHD

quickopencv.h

#pragma once
#include<opencv2/opencv.hpp>
using namespace cv;
class QuickDemo {
    public:
        void colorSpace_Demo(Mat &image);
        void mat_creation_demo();
        void pixel_visit_demo(Mat &image);
        void operators_demo(Mat &image);
        void tracking_bar_demo(Mat &image);
        void key_demo(Mat &image);
        void color_style_demo(Mat &image);
        void bitwise_demo(Mat &image);
        void channels_demo(Mat &image);
        void inrange_demo(Mat &image);
                void pixel_statistic_demo(Mat &image);
                void form_paint_random();
                void polyline_drawing_demo();
        void mouse_drawing_demo(Mat &image);
                void norm_demo(Mat &image);
                void resize_demo(Mat &image);
                void flip_demo(Mat &image);
                void rotate_demo(Mat &image);
                void video_demo(Mat &image);
};

quickdemo.cpp

void QuickDemo::video_demo(Mat &image) {
    //VideoCapture capture(0);  //获取当前设备摄像头视频
    VideoCapture capture("D:/images/video/example.mp4");  //获取该地址下的视频
    int frame_width = capture.get(CAP_PROP_FRAME_WIDTH);  //获取视频帧的宽高
    int frame_height = capture.get(CAP_PROP_FRAME_HEIGHT);
    int count = capture.get(CAP_PROP_FRAME_COUNT);  //获取视频的全部帧数
    double fps = capture.get(CAP_PROP_FPS);  //获取视频每秒帧数fps
    std::cout << "frame width: " << frame_width << std::endl;
    std::cout << "frame height: " << frame_height << std::endl;
    std::cout << "FPS: " << fps << std::endl;
    std::cout << "Number of Frames: " << count << std::endl;
    int fourcc = VideoWriter::fourcc('a','v','c','1');  //H264编码格式的fourcc code
    
    //VideoWriter writer(保存地址,fourcc编码格式code,帧率,保存视频的画面宽高,是否是彩色);
    VideoWriter writer("D:/test.mp4", fourcc, fps, Size(frame_width, frame_height), true);
    Mat frame;
    Mat frame1;
    while (true) {
        capture.read(frame);
        int h = frame.rows;  //获取视频每一帧的宽高
        int w = frame.cols;
        //flip(frame, frame, 1);  //摄像头需要翻转,视频不需要翻转
        if (frame.empty()) {
            break;
        }
        resize(frame, frame1, Size(w / 4, h / 4), 0, 0, INTER_LINEAR);  //缩放视频
        imshow("frame", frame1);  //显示缩放后的视频
        //colorSpace_Demo(frame);  //调用色彩空间转换函数,将视频转换为灰度图像及HSV图像并显示
        writer.write(frame);  //将每一帧保存到新的文件中
        // TODO: do something....
        int c = waitKey(10);
        if (c == 27) {  //退出
            break;
        }
    }
    
    //release
    capture.release();
    writer.release();
}

test440.cpp

#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>
using namespace cv;
using namespace std;
int main(int argc, char**argv) {
    // imread函数的第二个参数有很多,默认为IMREAD_COLOR,还有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,实现对不同图片的读取操作
    // B,G,R
    Mat src = imread("D:/images/lena.jpg");   //Mat为matrix,二维图像都是Mat类型,第一个参数为图片绝对路径
    if (src.empty()) {
        printf("could not load image...\n");
        return -1;
    }
    //namedWindow("输入窗口", WINDOW_FREERATIO);   //不管图片大小,都能进行调整,图像很小可以不使用这个函数
    //imshow("输入窗口", src);                    //第一个参数为窗口名
    QuickDemo qd;
    qd.video_demo(src);
    waitKey(0);                               //窗口停留时间,0为一直停留,数值为停留的毫秒数
    destroyAllWindows();                      //关闭所有打开的窗口
    return 0;
}

效果

image.png

运行过程中缺少H264编码器:

1、出现错误

image.png

2、到给出的网站中下载对应的dll文件

image.png

3、将该文件下载解压后放到opencv的bin目录下

image.png

4、再次运行正常

image.png

注意:H264对应的fourcc codeavc1! 具体原因可以自行百度,与OpenCV遵守的开源协议有关

2.23、图像直方图

图像直方图解释:

图像直方图使图像像素值的统计学特征,计算代价较小,具有图像平移、旋转、缩放不变性等众多优点,广泛地应用域图像处理的各个领域,特别是灰度图像的阈值分割、基于颜色的图像检索以及图像分类、反向投影跟踪。常见的分为灰度直方图颜色直方图

Bins是指直方图的大小范围,对于像素值取在0~255之间的,最少有256个bin,此外还可以有16、32、48、128等,256除以bin的大小应该是整数倍。

quickopencv.h

#pragma once
#include<opencv2/opencv.hpp>
using namespace cv;
class QuickDemo {
    public:
        void colorSpace_Demo(Mat &image);
        void mat_creation_demo();
        void pixel_visit_demo(Mat &image);
        void operators_demo(Mat &image);
        void tracking_bar_demo(Mat &image);
        void key_demo(Mat &image);
        void color_style_demo(Mat &image);
        void bitwise_demo(Mat &image);
        void channels_demo(Mat &image);
        void inrange_demo(Mat &image);
                void pixel_statistic_demo(Mat &image);
                void form_paint_random();
                void polyline_drawing_demo();
        void mouse_drawing_demo(Mat &image);
                void norm_demo(Mat &image);
                void resize_demo(Mat &image);
                void flip_demo(Mat &image);
                void rotate_demo(Mat &image);
                void video_demo(Mat &image);
                void histogram_demo(Mat &image);
};

quickdemo.cpp

void QuickDemo::histogram_demo(Mat &image) {
    //三通道分离
    std::vector<Mat> bgr_plane;  //定义Mat类型的集合,用来保存三通道数据
    split(image, bgr_plane);  //将图像三通道分离,保存到定义的集合中
    //定义参数变量
    const int channels[1] = { 0 };
    const int bins[1] = { 256 };  //总共256个灰度级别,bins[中括号内为该变量一共有几个数值]
    float hranges[2] = { 0,255 };  //每个通道取值范围0-255
    const float* ranges[1] = { hranges };
    Mat b_hist;
    Mat g_hist;
    Mat r_hist;
    //计算Blue,Green,Red通道的直方图
        //calcHist(输入图像指针,输入图像个数,统计直方图的第几通道,mask()只统计不为0的部分,直方图计算的输出值,输出直方图的维度由channels指定,每个维度分成多少个区间,统计像素值的区间)
    calcHist(&bgr_plane[0], 1, 0, Mat(), b_hist, 1, bins, ranges);
    calcHist(&bgr_plane[1], 1, 0, Mat(), g_hist, 1, bins, ranges);
    calcHist(&bgr_plane[2], 1, 0, Mat(), r_hist, 1, bins, ranges);
    //显示直方图
    int hist_w = 512;
    int hist_h = 400;
    int bin_w = cvRound((double)hist_w / bins[0]);
    Mat histImage = Mat::zeros(hist_h, hist_w,CV_8UC3);
    //归一化直方图数据
    normalize(b_hist, b_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
    normalize(g_hist, g_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
    normalize(r_hist, r_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
    //绘制直方图曲线
    for (int i = 1; i < bins[0]; i++) {
        line(histImage, Point(bin_w*(i - 1), hist_h - cvRound(b_hist.at<float>(i - 1))),
            Point(bin_w*(i), hist_h - cvRound(b_hist.at<float>(i))), Scalar(255, 0, 0), 2, LINE_AA, 0);
        line(histImage, Point(bin_w*(i - 1), hist_h - cvRound(g_hist.at<float>(i - 1))),
            Point(bin_w*(i), hist_h - cvRound(b_hist.at<float>(i))), Scalar(0, 255, 0), 2, LINE_AA, 0);
        line(histImage, Point(bin_w*(i - 1), hist_h - cvRound(r_hist.at<float>(i - 1))),
            Point(bin_w*(i), hist_h - cvRound(b_hist.at<float>(i))), Scalar(0, 0, 255), 2, LINE_AA, 0);
    }
    //显示直方图
    namedWindow("Histogram Demo", WINDOW_AUTOSIZE);
    imshow("Histogram Demo", histImage);
}

test440.cpp

#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>
using namespace cv;
using namespace std;
int main(int argc, char**argv) {
    // imread函数的第二个参数有很多,默认为IMREAD_COLOR,还有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,实现对不同图片的读取操作
    // B,G,R
    Mat src = imread("D:/images/flower.jpg");   //Mat为matrix,二维图像都是Mat类型,第一个参数为图片绝对路径
    if (src.empty()) {
        printf("could not load image...\n");
        return -1;
    }
    //namedWindow("输入窗口", WINDOW_FREERATIO);   //不管图片大小,都能进行调整,图像很小可以不使用这个函数
    imshow("输入窗口", src);                    //第一个参数为窗口名
    QuickDemo qd;
    qd.histogram_demo(src);
    waitKey(0);                               //窗口停留时间,0为一直停留,数值为停留的毫秒数
    destroyAllWindows();                      //关闭所有打开的窗口
    return 0;
}

效果

image.png

2.24、二维直方图

quickopencv.h

#pragma once
#include<opencv2/opencv.hpp>
using namespace cv;
class QuickDemo {
    public:
        void colorSpace_Demo(Mat &image);
        void mat_creation_demo();
        void pixel_visit_demo(Mat &image);
        void operators_demo(Mat &image);
        void tracking_bar_demo(Mat &image);
        void key_demo(Mat &image);
        void color_style_demo(Mat &image);
        void bitwise_demo(Mat &image);
        void channels_demo(Mat &image);
        void inrange_demo(Mat &image);
                void pixel_statistic_demo(Mat &image);
                void form_paint_random();
                void polyline_drawing_demo();
        void mouse_drawing_demo(Mat &image);
                void norm_demo(Mat &image);
                void resize_demo(Mat &image);
                void flip_demo(Mat &image);
                void rotate_demo(Mat &image);
                void video_demo(Mat &image);
                void histogram_demo(Mat &image);
                void histogram_2d_demo(Mat &image);
};

quickdemo.cpp

void QuickDemo::histogram_2d_demo(Mat &image) {
    //2D直方图
    Mat hsv, hs_hist;
    cvtColor(image, hsv, COLOR_BGR2HSV);  //输入图像色彩空间转化
    int hbins = 30, sbins = 32;  //H通道分为30个bins,S通道分为32个bins
    int hist_bins[] = { hbins,sbins };
    float h_range[] = { 0,180 };  //图像H通道取值范围
    float s_range[] = { 0,256 };  //图像S通道取值范围
    const float* hs_ranges[] = { h_range,s_range };
    int hs_channels[] = { 0,1 };
    //calcHist(输入图像,输入图像个数,输入图像的通道,mask处理值不为0的部分,输出结果,输入直方图的维度,每个维度分成多少区间,每个维度取值范围,)
    calcHist(&hsv, 1, hs_channels, Mat(), hs_hist, 2, hist_bins, hs_ranges, true, false);
    double maxVal = 0;
    minMaxLoc(hs_hist, 0, &maxVal, 0, 0);  //求图像全局最大最小值
    int scale = 10;
    Mat hist2d_image = Mat::zeros(sbins*scale, hbins*scale, CV_8UC3);
    Mat hist2d_image_back = Mat::zeros(sbins*scale, hbins*scale, CV_8UC3);
    for (int h = 0; h < hbins; h++) {
        for (int s = 0; s < sbins; s++) {
            float binVal = hs_hist.at<float>(h, s);
            int intensity = cvRound(binVal * 255 / maxVal);
            rectangle(hist2d_image, Point(h*scale, s*scale), 
                Point((h + 1)*scale - 1, (s + 1)*scale - 1), 
                Scalar::all(intensity), 
                -1);
        }
    }
    applyColorMap(hist2d_image, hist2d_image_back, COLORMAP_JET);
    imshow("H-S Histogram", hist2d_image);
    imshow("H-S Histogram_back", hist2d_image_back);
    imwrite("D:/hist_2d.png", hist2d_image);
}

test440.cpp

#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>
using namespace cv;
using namespace std;
int main(int argc, char**argv) {
    // imread函数的第二个参数有很多,默认为IMREAD_COLOR,还有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,实现对不同图片的读取操作
    // B,G,R
    Mat src = imread("D:/images/flower.jpg");   //Mat为matrix,二维图像都是Mat类型,第一个参数为图片绝对路径
    if (src.empty()) {
        printf("could not load image...\n");
        return -1;
    }
    //namedWindow("输入窗口", WINDOW_FREERATIO);   //不管图片大小,都能进行调整,图像很小可以不使用这个函数
    imshow("输入窗口", src);                    //第一个参数为窗口名
    QuickDemo qd;
    qd.histogram_2d_demo(src);
    waitKey(0);                               //窗口停留时间,0为一直停留,数值为停留的毫秒数
    destroyAllWindows();                      //关闭所有打开的窗口
    return 0;
}

效果

image.png

2.25、直方图均衡化

直方图均衡化的概念:

直方图均衡化(Histogram Equalization)是一种增强图像对比度(Image Contrast)的方法,其主要思想是将一副图像的直方图分布通过累积分布函数变成近似均匀分布,从而增强图像的对比度。为了将原图像的亮度范围进行扩展, 需要一个映射函数, 将原图像的像素值均衡映射到新直方图中, 这个映射函数有两个条件:

①不能打乱原有的像素值大小顺序, 映射后亮、 暗的大小关系不能改变;

② 映射后必须在原有的范围内,即像素映射函数的值域应在0和255之间;

综合以上两个条件,累积分布函数是个好的选择,因为累积分布函数是单调增函数(控制大小关系),并且值域是0到1(控制越界问题),所以直方图均衡化中使用的是累积分布函数。

累积分布函数的数学原理:

因为图像由一个个像素点组成,所以图像直方图均衡化是通过离散形式的累积分布函数求解的,直方图均衡化过程中,映射方法是:

Sk=∑j=0knjnk=0,1,2,...,L−1Sk=∑j=0knjnk=0,1,2,...,L−1

其中,S_k指当前灰度级经过累积分布函数映射后的值,n是图像中像素的总和,n_j是当前灰度级的像素个数,L是图像中的灰度级总数。

直方图均衡化的步骤:

①依次扫描原始灰度图像的每一个像素, 计算出图像的灰度直方图;

②计算灰度直方图的累积分布函数;

③根据累积分布函数和直方图均衡化原理得到输入与输出之间的映射关系。

④最后根据映射关系得到结果进行图像变换

直观理解直方图均衡化原理及过程:

image.png

quickopencv.h

#pragma once
#include<opencv2/opencv.hpp>
using namespace cv;
class QuickDemo {
    public:
        void colorSpace_Demo(Mat &image);
        void mat_creation_demo();
        void pixel_visit_demo(Mat &image);
        void operators_demo(Mat &image);
        void tracking_bar_demo(Mat &image);
        void key_demo(Mat &image);
        void color_style_demo(Mat &image);
        void bitwise_demo(Mat &image);
        void channels_demo(Mat &image);
        void inrange_demo(Mat &image);
                void pixel_statistic_demo(Mat &image);
                void form_paint_random();
                void polyline_drawing_demo();
        void mouse_drawing_demo(Mat &image);
                void norm_demo(Mat &image);
                void resize_demo(Mat &image);
                void flip_demo(Mat &image);
                void rotate_demo(Mat &image);
                void video_demo(Mat &image);
                void histogram_demo(Mat &image);
                void histogram_2d_demo(Mat &image);
                void histogram_eq_demo(Mat &image);
};

quickdemo.cpp

void QuickDemo::histogram_eq_demo(Mat &image) {
    Mat gray;
    cvtColor(image, gray, COLOR_BGR2GRAY);
    imshow("灰度图像", gray);
    Mat dst;
    equalizeHist(gray, dst);
    imshow("直方图均衡化演示", dst);
}

test440.cpp

#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>
using namespace cv;
using namespace std;
int main(int argc, char**argv) {
    // imread函数的第二个参数有很多,默认为IMREAD_COLOR,还有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,实现对不同图片的读取操作
    // B,G,R
    Mat src = imread("D:/images/flower.jpg");   //Mat为matrix,二维图像都是Mat类型,第一个参数为图片绝对路径
    if (src.empty()) {
        printf("could not load image...\n");
        return -1;
    }
    //namedWindow("输入窗口", WINDOW_FREERATIO);   //不管图片大小,都能进行调整,图像很小可以不使用这个函数
    imshow("输入窗口", src);                    //第一个参数为窗口名
    QuickDemo qd;
    qd.histogram_eq_demo(src);
    waitKey(0);                               //窗口停留时间,0为一直停留,数值为停留的毫秒数
    destroyAllWindows();                      //关闭所有打开的窗口
    return 0;
}

效果

image.png

2.26、图像卷积操作

卷积运算原理示意图:

image.png

quickopencv.h

#pragma once
#include<opencv2/opencv.hpp>
using namespace cv;
class QuickDemo {
    public:
        void colorSpace_Demo(Mat &image);
        void mat_creation_demo();
        void pixel_visit_demo(Mat &image);
        void operators_demo(Mat &image);
        void tracking_bar_demo(Mat &image);
        void key_demo(Mat &image);
        void color_style_demo(Mat &image);
        void bitwise_demo(Mat &image);
        void channels_demo(Mat &image);
        void inrange_demo(Mat &image);
                void pixel_statistic_demo(Mat &image);
                void form_paint_random();
                void polyline_drawing_demo();
        void mouse_drawing_demo(Mat &image);
                void norm_demo(Mat &image);
                void resize_demo(Mat &image);
                void flip_demo(Mat &image);
                void rotate_demo(Mat &image);
                void video_demo(Mat &image);
                void histogram_demo(Mat &image);
                void histogram_2d_demo(Mat &image);
                void histogram_eq_demo(Mat &image);
                void blur_demo(Mat &image);
};

quickdemo.cpp

void QuickDemo::blur_demo(Mat &image) {
    Mat dst01, dst02, dst03, dst04, dst05;
        //blur为均值卷积,卷积后求平均值得到对应的值
        //blur(输入图像,输出图像,卷积核大小,卷积输出位置默认为中心(-1,-1)),默认均值卷积核,卷积核越大模糊程度越高
    blur(image, dst01, Size(3, 3), Point(-1, -1));
    blur(image, dst02, Size(13, 13), Point(-1, -1));
    blur(image, dst03, Size(23, 23), Point(-1, -1));
    blur(image, dst04, Size(13, 1), Point(-1, -1));
    blur(image, dst05, Size(1, 13), Point(-1, -1));
    
    imshow("图像模糊01", dst01);
    imshow("图像模糊02", dst02);
    imshow("图像模糊03", dst03);
    imshow("图像模糊04", dst04);
    imshow("图像模糊05", dst05);
}

test440.cpp

#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>
using namespace cv;
using namespace std;
int main(int argc, char**argv) {
    // imread函数的第二个参数有很多,默认为IMREAD_COLOR,还有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,实现对不同图片的读取操作
    // B,G,R
    Mat src = imread("D:/images/flower.jpg");   //Mat为matrix,二维图像都是Mat类型,第一个参数为图片绝对路径
    if (src.empty()) {
        printf("could not load image...\n");
        return -1;
    }
    //namedWindow("输入窗口", WINDOW_FREERATIO);   //不管图片大小,都能进行调整,图像很小可以不使用这个函数
    imshow("输入窗口", src);                    //第一个参数为窗口名
    QuickDemo qd;
    qd.blur_demo(src);
    waitKey(0);                               //窗口停留时间,0为一直停留,数值为停留的毫秒数
    destroyAllWindows();                      //关闭所有打开的窗口
    return 0;
}

效果

image.png

2.27、高斯模糊

高斯模糊计算公式:

高斯核函数符合空间正态分布(正态分布又名高斯分布),越靠近卷积核中心的值权重越大

高斯函数示意图:

image.png

高斯模糊计算公式:

\[G(x,y)=12πσ2e−(x2+y2)/(2σ2)G(x,y)=12πσ2e−(x2+y2)/(2σ2) \]

该计算公式可看作是二维正态分布函数,是根据一维高斯函数推导来的,一维高斯函数就是正态分布函数。

使用高斯模糊计算公式根据输入的参数计算高斯权重矩阵,具体计算方法可参考该文章:https://blog.csdn.net/qq_32515081/article/details/115006246。

得到权重矩阵后,按卷积核计算规则将每个值乘以对应的矩阵再求和即可得到中心点对应的值。

quickopencv.h

#pragma once
#include<opencv2/opencv.hpp>
using namespace cv;
class QuickDemo {
    public:
        void colorSpace_Demo(Mat &image);
        void mat_creation_demo();
        void pixel_visit_demo(Mat &image);
        void operators_demo(Mat &image);
        void tracking_bar_demo(Mat &image);
        void key_demo(Mat &image);
        void color_style_demo(Mat &image);
        void bitwise_demo(Mat &image);
        void channels_demo(Mat &image);
        void inrange_demo(Mat &image);
                void pixel_statistic_demo(Mat &image);
                void form_paint_random();
                void polyline_drawing_demo();
        void mouse_drawing_demo(Mat &image);
                void norm_demo(Mat &image);
                void resize_demo(Mat &image);
                void flip_demo(Mat &image);
                void rotate_demo(Mat &image);
                void video_demo(Mat &image);
                void histogram_demo(Mat &image);
                void histogram_2d_demo(Mat &image);
                void histogram_eq_demo(Mat &image);
                void blur_demo(Mat &image);
                void gaussian_blue_demo(Mat &image);
};

quickdemo.cpp

void QuickDemo::gaussian_blue_demo(Mat &image) {
    Mat dst01, dst02, dst03;
        //GaussianBlur(输入图像,输出图像,卷积核大小,高斯函数σ的值(默认σx=σy),边缘处理方式)
    GaussianBlur(image, dst01, Size(5, 5), 15);
    GaussianBlur(image, dst02, Size(3, 3), 15);
    GaussianBlur(image, dst03, Size(0, 0), 15);
    imshow("高斯模糊01",dst01);
    imshow("高斯模糊02",dst02);
    imshow("高斯模糊03",dst03);
}

test440.cpp

#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>
using namespace cv;
using namespace std;
int main(int argc, char**argv) {
    // imread函数的第二个参数有很多,默认为IMREAD_COLOR,还有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,实现对不同图片的读取操作
    // B,G,R
    Mat src = imread("D:/images/flower.jpg");   //Mat为matrix,二维图像都是Mat类型,第一个参数为图片绝对路径
    if (src.empty()) {
        printf("could not load image...\n");
        return -1;
    }
    //namedWindow("输入窗口", WINDOW_FREERATIO);   //不管图片大小,都能进行调整,图像很小可以不使用这个函数
    imshow("输入窗口", src);                    //第一个参数为窗口名
    QuickDemo qd;
    qd.gaussian_blue_demo(src);
    waitKey(0);                               //窗口停留时间,0为一直停留,数值为停留的毫秒数
    destroyAllWindows();                      //关闭所有打开的窗口
    return 0;
}

效果

image.png

2.28、高斯双边模糊

双边滤波原理:

  • 空间距离:当前点距离滤波模板中心点的欧式距离。

  • 灰度距离:当前点距离滤波模板中心点的灰度的差值的绝对值。

双边滤波的核函数是空间域核像素范围域核的综合结果:

1.在图像的平坦区域,像素值变化很小,那么像素差值接近于0,对应的像素范围域权重接近于1,此时空间域权重起主要作用,相当于进行高斯模糊;

2.在图像的边缘区域,像素值变化很大,那么像素差值大,对应的像素范围域权重变大,即使距离远空间域权重小,加上像素域权重总的系数也较大,从而保护了边缘的信息。

双边滤波在突变的边缘上,使用了像素差权重,很好的保留了边缘。

quickopencv.h

#pragma once
#include<opencv2/opencv.hpp>
using namespace cv;
class QuickDemo {
    public:
        void colorSpace_Demo(Mat &image);
        void mat_creation_demo();
        void pixel_visit_demo(Mat &image);
        void operators_demo(Mat &image);
        void tracking_bar_demo(Mat &image);
        void key_demo(Mat &image);
        void color_style_demo(Mat &image);
        void bitwise_demo(Mat &image);
        void channels_demo(Mat &image);
        void inrange_demo(Mat &image);
                void pixel_statistic_demo(Mat &image);
                void form_paint_random();
                void polyline_drawing_demo();
        void mouse_drawing_demo(Mat &image);
                void norm_demo(Mat &image);
                void resize_demo(Mat &image);
                void flip_demo(Mat &image);
                void rotate_demo(Mat &image);
                void video_demo(Mat &image);
                void histogram_demo(Mat &image);
                void histogram_2d_demo(Mat &image);
                void histogram_eq_demo(Mat &image);
                void blur_demo(Mat &image);
                void gaussian_blue_demo(Mat &image);
                void bifilter_demo(Mat &image);
};

quickdemo.cpp

void QuickDemo::bifilter_demo(Mat &image) {
    Mat dst;
    bilateralFilter(image, dst, 0, 100, 10);
    imshow("双边模糊", dst);
}

test440.cpp

#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>
using namespace cv;
using namespace std;
int main(int argc, char**argv) {
    // imread函数的第二个参数有很多,默认为IMREAD_COLOR,还有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,实现对不同图片的读取操作
    // B,G,R
    Mat src = imread("D:/images/lena.jpg");   //Mat为matrix,二维图像都是Mat类型,第一个参数为图片绝对路径
    if (src.empty()) {
        printf("could not load image...\n");
        return -1;
    }
    //namedWindow("输入窗口", WINDOW_FREERATIO);   //不管图片大小,都能进行调整,图像很小可以不使用这个函数
    imshow("输入窗口", src);                    //第一个参数为窗口名
    QuickDemo qd;
    qd.bifilter_demo(src);
    waitKey(0);                               //窗口停留时间,0为一直停留,数值为停留的毫秒数
    destroyAllWindows();                      //关闭所有打开的窗口
    return 0;
}

效果

image.png

3、案例:实时人脸识别

先下载三个文件置于opencv的face_detector路径下:D:\environment\opencv\sources\samples\dnn\face_detector

下载地址及文件如下:

image.png

quickopencv.h

#pragma once
#include<opencv2/opencv.hpp>
using namespace cv;
class QuickDemo {
    public:
        void colorSpace_Demo(Mat &image);
        void mat_creation_demo();
        void pixel_visit_demo(Mat &image);
        void operators_demo(Mat &image);
        void tracking_bar_demo(Mat &image);
        void key_demo(Mat &image);
        void color_style_demo(Mat &image);
        void bitwise_demo(Mat &image);
        void channels_demo(Mat &image);
        void inrange_demo(Mat &image);
                void pixel_statistic_demo(Mat &image);
                void form_paint_random();
                void polyline_drawing_demo();
        void mouse_drawing_demo(Mat &image);
                void norm_demo(Mat &image);
                void resize_demo(Mat &image);
                void flip_demo(Mat &image);
                void rotate_demo(Mat &image);
                void video_demo(Mat &image);
                void histogram_demo(Mat &image);
                void histogram_2d_demo(Mat &image);
                void histogram_eq_demo(Mat &image);
                void blur_demo(Mat &image);
                void gaussian_blue_demo(Mat &image);
                void bifilter_demo(Mat &image);
                void face_detection_demo();
};

quickdemo.cpp

#include<quickopencv.h>
#include<opencv2/dnn.hpp>
using namespace cv;
using namespace std;
void QuickDemo::face_detection_demo() {
    std::string root_dir = "D:/environment/opencv/sources/samples/dnn/face_detector/";
    //读取深度神经网络 dnn::readNetFromTensorflow(路径+模型文件名,路径+配置文件名)
    dnn::Net net = dnn::readNetFromTensorflow(root_dir + "opencv_face_detector_uint8.pb", root_dir + "opencv_face_detector.pbtxt");
    VideoCapture capture("D:/images/video/example_dsh.mp4");  //加载一段视频
    Mat frame;
    while (true) {
        capture.read(frame);
        if (frame.empty()) {
            break;
        }
        //张量(tensor)可以看作是一个多维矩阵,这里定义一个张量blob
        //dnn::blobFromImage(输入图像,scale factor 1.0表示色彩空间还是0-255,模型要求的输入尺寸,模型要求的均值(models.yml文件中的mean值),是否进行通道交换(models.yml文件中),是否要剪切图像)
        Mat blob = dnn::blobFromImage(frame, 1.0, Size(300, 300), Scalar(104, 177, 123), false, false);
        //将输入图像张量输入到深度神经网络中
        net.setInput(blob);  //输入的blob格式 NCHW 多少个图像,输入通道数,高度,宽度
        //对输入图片进行推理
        Mat probs = net.forward();  //输出结果(多少张图像每张图有对应编号,每张图第几个批次第几张图,多少框,每个框有7列)
        Mat detectionMat(probs.size[2], probs.size[3], CV_32F, probs.ptr<float>());  //只获取输出结果的后两部分
        //解析结果
        for (int i = 0; i < detectionMat.rows; i++) {  //前两个值代表类型和index,第三个值是人脸得分
            float confidence = detectionMat.at<float>(i, 2);  //判断是否是人脸的部分
            if (confidence > 0.5) {  //得到人脸部分矩形的左上角和右下角坐标,用户绘制检测框
                int x1 = static_cast<int>(detectionMat.at<float>(i, 3)*frame.cols);
                int y1 = static_cast<int>(detectionMat.at<float>(i, 4)*frame.rows);
                int x2 = static_cast<int>(detectionMat.at<float>(i, 5)*frame.cols);
                int y2 = static_cast<int>(detectionMat.at<float>(i, 6)*frame.rows);
                Rect box(x1, y1, x2 - x1, y2 - y1);
                rectangle(frame, box, Scalar(0, 0, 255), 2, 8, 0);
            }
        }
        imshow("人脸检测演示", frame);
        //TODO: do something...
        int c = waitKey(1);
        if (c == 27) { //退出
            break;
        }
        
    }
}

深度神经网络模型models.yml配置文件说明:

image.png

test440.cpp

#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>
using namespace cv;
using namespace std;
int main(int argc, char**argv) {
    // imread函数的第二个参数有很多,默认为IMREAD_COLOR,还有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,实现对不同图片的读取操作
    // B,G,R
    Mat src = imread("D:/images/lena.jpg");   //Mat为matrix,二维图像都是Mat类型,第一个参数为图片绝对路径
    if (src.empty()) {
        printf("could not load image...\n");
        return -1;
    }
    //namedWindow("输入窗口", WINDOW_FREERATIO);   //不管图片大小,都能进行调整,图像很小可以不使用这个函数
    //imshow("输入窗口", src);                    //第一个参数为窗口名
    QuickDemo qd;
    qd.face_detection_demo();
    waitKey(0);                               //窗口停留时间,0为一直停留,数值为停留的毫秒数
    destroyAllWindows();                      //关闭所有打开的窗口
    return 0;
}

效果

image.png

本文转载自:

OpenCV4之C++入门详解 (上):

https://developer.aliyun.com/article/1042462?spm=a2c6h.24874632.expert-profile.82.99ae65a1drGJK9

OpenCV4之C++入门详解 (中):

https://developer.aliyun.com/article/1042464?spm=a2c6h.24874632.expert-profile.81.99ae65a1drGJK9

OpenCV4之C++入门详解 (下):

https://developer.aliyun.com/article/1042465?spm=a2c6h.24874632.expert-profile.80.99ae65a1drGJK9

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

标签:Mat,int,demo,image,C++,详解,OpenCV4,include,void
From: https://www.cnblogs.com/L707/p/16944556.html

相关文章

  • Java方法详解
    何为方法Java方法是语句的集合,他们在一起执行一个功能方法是解决一类问题的步骤的有序组合方法包含于类或对象中方法在程序中被创建,在其他地方被引用设计......
  • C++ 设计一个类模板,有数据成员T data[size],有求最大值的方法getMax()和排序的方法sort
    #include<iostream>#include<string>usingnamespacestd;template<typenameT,intsize>classData{Tdata[size];public:Data(){cout<<......
  • 苹果App Store上传应用流程详解
    在向AppStore提交应用之前,开发者首先要成为苹果iOS开发者项目的成员,每年向苹果缴纳99美元或199美元的费用(具体申请方法后期更新)。其次创建相应的证书Development是开发环境......
  • Hbase协处理器详解
    Hbase协处理器一、简述二、协处理器类型    2.1Observer协处理器    2.2Endpoint协处理器三、协处理的加载方式四、静态加载与卸载    4.1静态加......
  • 苹果App Store上传应用流程详解
    在向AppStore提交应用之前,开发者首先要成为苹果iOS开发者项目的成员,每年向苹果缴纳99美元或199美元的费用(具体申请方法后期更新)。其次创建相应的证书Development是开发环......
  • C++Primer 第4章
    第4章表达式C++语言提供了一套丰富的运算符,并定义了这些运算符作用于内置类型的运算对象时所执行的操作。同时,当运算对象是类类型时,C++语言也允许由用户指定上述运算符的......
  • 输出10个数中只出现一次的数的个数c++实现
    题目描述针对一个可能含有重复整数出现的一维整数数组【10个元素】,请输出只出现过一次的整数元素的数目。输入31637575894729108931输出4样例输入Copy)3......
  • 详解ASP.NET4 GridView新增4大排序样式
    原文发表在:http://tech.it168.com/a2010/1012/1112/000001112829.shtml上与ASP.NET的其他Web控件一能够,Gridview控件拥有很多不同的CSS样式属性设......
  • (翻译)详解2010年最佳开源企业应用软件
    偶翻译的一篇文,原文发表在​​​http://publish.itpub.net/a2010/0907/1100/000001100373.shtml​​​自从RichardStallman发布了他的文字编辑器,......
  • 【JUC】交换器Exchanger详解
    欢迎关注专栏【JAVA并发】前言JDK中提供了不少的同步工具,现在分享一个相对比较冷门的同步工具——交换器(Exchanger)。你知道Exchanger的作用是什么吗?实现机制是什么?可以......