4 OpenCV 图像处理

首页




颜色模型转换

RGB颜色模型在这里插入图片描述
OpenCV中顺序是相反的,为 BGR ,分别对应 blue(蓝), green (绿), red(红)。此为三通道图像时,且每个通道有256个等级,对应0~255。四通道时再加一个透明度,此时为BRGA,没有透明度需求时就变为BGR。
YUV颜色模型YUV模型是电视信号系统采用的颜色编码方式。分别代表像素的 亮度(Y)红色分量与亮度的信号差值(U)蓝色与亮度的差值(V)

Y = 0.229R + 0.587G + 0.114B
U = -0.147R - 0.289G + 0.436B
V = 0.615R - 0.515G - 0.100B
R = Y + 1.14V
G = Y - 0.39U - 0.58V
B = Y + 2.03U
HSV颜色模型在这里插入图片描述
HSV是 色度 (Hue)饱和度 (Saturation)亮度 (Value) 的简写.色度是色彩的基本属性,就是平常说的颜色; 饱和度是指颜色的纯度, 取值0%~100%; 亮度是颜色的明暗程度,其取值由0到计算机中允许的最大值. 相比于RGB模型3个颜色分量与最终颜色联系不直观的缺点, HSV模型更加符合人类感知颜色的方式: 颜色、深浅及亮暗.
Lab颜色模型在这里插入图片描述
Lab颜色模型弥补了RGB模型的不足,是一种设备无关和基于生理特征的颜色模型. 在模型中, L 表示亮度 (Luminosity), a 和 b 是两个颜色通道, 两者的取值区间都是 -128~127, 其中 a 通道数值由小到大对应的颜色是从绿色变成红色, b 通道数值由小到达对应的颜色是由蓝色变成黄色.
GRAY颜色模型此模型非彩色,是一个灰度图像模型,分为256个等级,取值0~255,与RGB对应关系的常用转换式为:

GRAY = 0.3R + 0.59G + 0.11B
/**
 * @author IYATT-yx
 * @date 2021/2/3
 * @brief 颜色模型转换 (通过摄像头获取图像)
 */
#include "opencv2/opencv.hpp"
#include <iostream>

int main()
{
    cv::VideoCapture camera(-1);
    if (!camera.isOpened())
    {
        std::cout << "摄像头打开失败" << std::endl;
        exit(EXIT_FAILURE);
    }
    cv::Mat src, gray, HSV, YUV, Lab;

    while (camera.read(src))
    {
        // 默认CV_8U,转为CV_32F. 缩放到 0~1
        src.convertTo(src, CV_32F, 1.0 / 255);
        cv::imshow("src", src);

        // gray
        cv::cvtColor(src, gray, cv::COLOR_BGR2GRAY);
        cv::imshow("gray", gray);

        // HSV
        cv::cvtColor(src, HSV, cv::COLOR_BGR2HSV);
        cv::imshow("HSV", HSV);

        // YUV
        cv::cvtColor(src, YUV, cv::COLOR_BGR2YUV);
        cv::imshow("YUV", YUV);

        // Lab
        cv::cvtColor(src, Lab, cv::COLOR_BGR2Lab);
        cv::imshow("Lab", Lab);

        if (cv::waitKey(40) == 27)
        {
            break;
        }
    }
    camera.release();
}

在这里插入图片描述





多通道分离与合并

/**
 * @author IYATT-yx
 * @date 2021/2/3
 * @brief 多通道分离与合并
 */
#include "opencv2/opencv.hpp"
#include <iostream>
#include <vector>

int main()
{
    // RGB三基色
    cv::Mat B(200, 200, CV_8UC1, cv::Scalar(200));
    cv::Mat G(200, 200, CV_8UC1, cv::Scalar(100));
    cv::Mat R(200, 200, CV_8UC1, cv::Scalar(255));
    // 将三基色的矩阵添加到一个vector容器中
    std::vector<cv::Mat> mergeVector;
    mergeVector.push_back(B);
    mergeVector.push_back(G);
    mergeVector.push_back(R);
    // 合并
    cv::Mat mergeMat;
    cv::merge(mergeVector, mergeMat);
    cv::imshow("mergeMat", mergeMat);

    // 分离
    std::vector<cv::Mat> splitVector;
    cv::split(mergeMat, splitVector);

    cv::imshow("B", splitVector[0]);
    cv::imshow("G", splitVector[1]);
    cv::imshow("R", splitVector[2]);

    cv::waitKey(0);
}

在这里插入图片描述





图像拼接

/**
 * @author IYATT-yx
 * @date 2021/2/3
 * @brief 图像拼接
 */
#include "opencv2/opencv.hpp"

int main()
{
    cv::Mat img1(200, 200, CV_8UC3, cv::Scalar(0, 0, 255));
    cv::imshow("img1", img1);
    cv::Mat img2(200, 200, CV_8UC3, cv::Scalar(255, 0, 0));
    cv::imshow("img2", img2);

    // 先水平方向拼接
    cv::Mat img3, img4;
    cv::hconcat(img1, img2, img3);
    cv::imshow("img3", img3);
    cv::hconcat(img2, img1, img4);
    cv::imshow("img4", img4);

    // 竖直拼接
    cv::Mat img5;
    cv::vconcat(img3, img4, img5);
    cv::imshow("img5", img5);

    cv::waitKey(0);
}

在这里插入图片描述





图像翻转

/**
 * @author IYATT-yx
 * @date 2021/2/3
 * @brief 图像翻转
 */
#include "opencv2/opencv.hpp"

int main()
{
    cv::VideoCapture camera(-1);
    if (!camera.isOpened())
    {
        std::cout << "打开摄像头失败" << std::endl;
        exit(EXIT_FAILURE);
    }
    cv::Mat src;
    camera >> src;
    cv::imshow("camera", src);
    int leftRight = false;
    int upDown = false;

    cv::createTrackbar("左右翻转", "camera", &leftRight, 1);
    cv::createTrackbar("上下翻转", "camera", &upDown, 1);

    while (camera.read(src))    
    {
        // 左右翻转
        if (leftRight == true && upDown == false)
        {
            cv::flip(src, src, 1);
        }
        // 上下翻转
        else if (leftRight == false && upDown == true)
        {
            cv::flip(src, src, 0);
        }
        // 上下左右翻转
        else if (leftRight == true && upDown == true)
        {
            cv::flip(src, src, -1);
        }

        cv::imshow("camera", src);
        if (cv::waitKey(40) == 27)
        {
            break;
        }
    }

    camera.release();
}

在这里插入图片描述





图像仿射变换

图像的旋转,平移,缩放的统称

/**
 * @author IYATT-yx
 * @date 2021/2/3
 * @brief 图像仿射变换
 */
#include "opencv2/opencv.hpp"
#include <iostream>

int main()
{
    cv::VideoCapture camera(-1);
    if (!camera.isOpened())
    {
        std::cout << "摄像头打开失败" << std::endl;
        exit(EXIT_FAILURE);
    }
    cv::Mat src;
    camera >> src;
    cv::imshow("camera", src);

    // 旋转角度
    int angle = 0;
    // 缩放 (scale的值除以10为缩放比例)
    int scale = 10;
    // 三点仿射
    int flag = false;
    cv::createTrackbar("旋转", "camera", &angle, 360);
    cv::createTrackbar("缩放", "camera", &scale, 20);
    cv::createTrackbar("点仿射", "camera", &flag, 1);

    // 中心点
    cv::Point2f center((float)src.cols / 2, (float)src.rows / 2);
    std::cout << center.x << std::endl;
    std::cout << center.y << std::endl;
    // 尺寸
    cv::Size dsize(src.rows, src.cols);

    // 原始三点
    cv::Point2f srcPoints[3];
    srcPoints[0] = cv::Point2f(0, 0);
    srcPoints[1] = cv::Point2f(0, (float)(src.rows - 1));
    srcPoints[2] = cv::Point2f((float)(src.cols - 1), (float)(src.rows - 1));

    // 变换后
    cv::Point2f dstPoints[3];
    dstPoints[0] = cv::Point2f((float)src.cols * 11 / 100, (float)src.rows * 20 / 100);
    dstPoints[1] = cv::Point2f((float)src.cols * 15 / 100, (float)src.rows * 70 / 100);
    dstPoints[2] = cv::Point2f((float)src.cols * 81 / 100, (float)src.rows * 85 / 100);
    cv::Mat rotation1 = cv::getAffineTransform(srcPoints, dstPoints);

    while (camera.read(src))
    {
        cv::Mat rotation2 = cv::getRotationMatrix2D(center, angle, static_cast<double>(scale) / 10.0);
        cv::warpAffine(src, src, rotation2, dsize);

        if (flag == true)
        {
            cv::warpAffine(src, src, rotation1, dsize);
        }
        
        cv::imshow("camera", src);
        if (cv::waitKey(40) == 27)
        {
            break;
        }
    }

    camera.release();
}

在这里插入图片描述





透视变换

按照物体成像规律进行变换,将物体重新投影到新的成像平面


素材图片 (可在图片上右键 "图片另存为")
在这里插入图片描述

/**
 * @author IYATT-yx
 * @date 2021/2/3
 * @brief 图像透视变换
 */
#include "opencv2/opencv.hpp"
#include <iostream>

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        std::cout << "参数: 请输入所给的二维码素材图片路径" << std::endl;
        exit(EXIT_FAILURE);
    }
    cv::Mat src = cv::imread(argv[1]);
    if (src.empty())
    {
        std::cout << "图片读取失败,请确认是否存在" << std::endl;
        exit(EXIT_FAILURE);
    }

    // 二维码初始四角点坐标
    cv::Point2f srcPoints[4];
    srcPoints[0] = cv::Point2f(94, 374);
    srcPoints[1] = cv::Point2f(507, 380);
    srcPoints[2] = cv::Point2f(1, 623);
    srcPoints[3] = cv::Point2f(627, 627);

    // 透视变换后希望的四角点坐标
    cv::Point2f dstPoints[4];
    dstPoints[0] = cv::Point2f(0,0);
    dstPoints[1] = cv::Point2f(627, 0);
    dstPoints[2] = cv::Point2f(0, 627);
    dstPoints[3] = cv::Point2f(627, 627);

    // 计算透视变换矩阵
    cv::Mat rotation = cv::getPerspectiveTransform(srcPoints, dstPoints);
    // 透视变换投影
    cv::Mat dst;
    cv::warpPerspective(src, dst, rotation, src.size());
    cv::imshow("src", src);
    cv::imshow("dst", dst);
    cv::waitKey(0);
}

在这里插入图片描述





极坐标变换

将图像在直角坐标系与极坐标系中相互变换


素材 在图片上右键 "图片另存为"
在这里插入图片描述

/**
 * @author IYATT-yx
 * @date 2021/2/4
 * @brief 图像极坐标变换
 */
#include "opencv2/opencv.hpp"
#include <iostream>

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        std::cout << "参数: 请输入所给的素材图片的路径" << std::endl;
        exit(EXIT_FAILURE);
    }
    cv::Mat src = cv::imread(argv[1]);
    cv::imshow("src", src);
    cv::Mat dst;
    if (src.empty())
    {
        std::cout << "图片读取失败,请确认是否存在" << std::endl;
        exit(EXIT_FAILURE);
    }

    // 极坐标图像原点
    cv::Point2f center = cv::Point2f(static_cast<float>(src.cols) / 2, static_cast<float>(src.rows) / 2);
    // 正极坐标变换
    cv::warpPolar(src, dst, cv::Size(300, 600), center, center.x, cv::INTER_LINEAR + cv::WARP_POLAR_LINEAR);
    cv::imshow("dst1", dst);
    // 逆极坐标变换
    cv::warpPolar(dst, dst, cv::Size(src.cols, src.rows), center, center.x, cv::INTER_LINEAR + cv::WARP_POLAR_LINEAR + cv::WARP_INVERSE_MAP);
    cv::imshow("dst2", dst);

    cv::waitKey(0);
}

在这里插入图片描述





感兴趣的区域 (Region of Interest, ROI)

当我们只对一幅图像中的部分区域感兴趣,而原图又比较大,则带着非感兴趣的区域处理会消耗额外不必要的资源,因此希望从原图中截取部分图像后再处理,该区域则为 ROI

/**
 * @author IYATT-yx
 * @date 2021/2/4
 * @brief ROI
 */
#include "opencv2/opencv.hpp"
#include <iostream>

int main(int argc, char *argv[])
{
    if (argc != 3)
    {
        std::cout << "参数: 请输入两张图片的路径" << std::endl;
        exit(EXIT_FAILURE);
    }
    cv::Mat img1 = cv::imread(argv[1]);
    cv::resize(img1, img1, cv::Size(500, 500));
    cv::imshow("img1", img1);
    cv::Mat img2 = cv::imread(argv[2]);
    cv::resize(img2, img2, cv::Size(150, 150));
    cv::imshow("img2", img2);

    // 截图1
    // 左上角(x, y) 宽度 高度
    cv::Rect rect(38, 30, 68, 75);
    cv::Mat ROI1 = img2(rect);
    cv::imshow("ROI1", ROI1);

    // 截图2
    // (行取值范围, 列取值范围)
    cv::Mat ROI2 = img2(cv::Range(30, 105), cv::Range(38, 106));
    // 用"="是浅拷贝 - 创建一个变量去访问数据,通过原变量和现变量都可以对同一数据做读写
    cv::Mat ROI2_copy = ROI2;
    cv::putText(ROI2_copy, "@@", cv::Point(5, 70), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(0, 0, 255));
    cv::imshow("ROI2", ROI2);

    // 插入图片
    // 浅拷贝img1中的ROI,准备将img2插入进去
    cv::Mat ROI3 = img1(cv::Rect(200, 200, img2.size().width, img2.size().height));
    // 将要插入的内容拷贝给ROI (深拷贝, 数据复制)
    img2.copyTo(ROI3);
    cv::imshow("插入图片", img1);

    cv::waitKey(0);
}

在这里插入图片描述





图像金字塔

在这里插入图片描述

  • 高斯金字塔
    构建图像的高斯金字塔是解决尺度不确定性的一种常用方法. 高斯金字塔是指通过下采样不断地将图像的尺寸缩小,进而在图像金字塔中包含多个尺寸的图像.一般情况下,高斯金字塔的底层为图像的原图,每往上一层就会通过下采样缩小一次图像的尺寸,通常尺寸会缩小为原来的一半.

  • 拉普拉斯金字塔
    和高斯金字塔相反,是通过上层小尺寸构建下层大尺寸的图像. 拉普拉斯金字塔有预测残差的作用.

/**
 * @author IYATT-yx
 * @date 2021/2/4
 * @brief 图像金字塔
 */
#include "opencv2/opencv.hpp"
#include <iostream>
#include <vector>
#include <string>

// 层数
#define LEVEL 3

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        std::cout << "参数: 请输入图片的路径" << std::endl;
        exit(EXIT_FAILURE);
    }
    cv::Mat src = cv::imread(argv[1]);
    if(src.empty())
    {
        std::cout << "图片读取错误,请检查是否存在" << std::endl;
        exit(EXIT_FAILURE);
    }

    // 构建高斯金字塔
    std::vector<cv::Mat> gauss;
    gauss.push_back(src);
    for (int i = 0; i < LEVEL; ++i)
    {
        cv::Mat temp;
        cv::pyrDown(gauss[i], temp);
        gauss.push_back(temp);
    }

    // 构建拉普拉斯金字塔
    std::vector<cv::Mat> lap;
    lap.push_back(gauss[LEVEL]);
    for (int i = LEVEL; i > 0; --i)
    {
        cv::Mat temp;
        cv::pyrUp(gauss[i], temp);
        lap.push_back(temp);
    }

    // 显示
    for (int i = 0; i <= LEVEL; ++i)
    {
        std::string number = std::to_string(i);
        cv::imshow("G" + number, gauss[i]);
        cv::imshow("L" + number, lap[i]);
    }

    cv::waitKey(0);
}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值