当前位置:首页 > 技术 > 正文内容

OpenCV 基础图像处理核心操作详解

访客 技术 2026年9月11日 10

图像通道解析

数字图像的色彩信息通常由多个通道叠加构成。对于标准彩色图像,一般采用红、绿、蓝三通道模型。通过 OpenCV 可快速获取图像的通道数量:

#include <opencv2/opencv.hpp>
#include <iostream>

int main() {
    cv::Mat sample = cv::imread("demo.jpg");
    if (sample.empty()) {
        std::cerr << "图像加载失败" << std::endl;
        return -1;
    }
    
    int channelCount = sample.channels();
    std::cout << "当前图像包含 " << channelCount << " 个通道" << std::endl;
    
    return 0;
}

掩膜运算机制

掩膜技术的核心在于构建二值化模板,通过与原图像执行按位与运算实现区域提取。以下示例展示如何创建圆形掩膜并提取感兴趣区域:

#include <opencv2/opencv.hpp>

int main() {
    cv::Mat origin = cv::imread("sample.jpg");
    if (origin.empty()) return -1;
    
    cv::Mat binaryMask = cv::Mat::zeros(origin.size(), CV_8UC1);
    cv::circle(binaryMask, cv::Point(origin.cols/2, origin.rows/2), 100, cv::Scalar(255), -1);
    
    cv::Mat extractedRegion;
    origin.copyTo(extractedRegion, binaryMask);
    
    cv::imshow("原始图像", origin);
    cv::imshow("二值掩膜", binaryMask);
    cv::imshow("提取结果", extractedRegion);
    cv::waitKey(0);
    return 0;
}

Mat 矩阵运算基础

OpenCV 的 Mat 类支持灵活的矩阵创建与运算。注意:使用 imshow 显示时,数据类型应为 CV_8U(无符号 8 位整数)格式:

#include <opencv2/opencv.hpp>
#include <iostream>

int main() {
    cv::Mat matrixA = (cv::Mat_<int>(3, 3) << 10, 20, 30, 40, 50, 60, 70, 80, 90);
    cv::Mat matrixB = cv::Mat::ones(3, 3, CV_32SC1) * 5;
    
    cv::Mat sumMatrix = matrixA + matrixB;
    std::cout << "矩阵相加结果:\n" << sumMatrix << std::endl;
    
    cv::Mat converted;
    sumMatrix.convertTo(converted, CV_8U);
    
    return 0;
}

基础几何对象操作

坐标点定义

图像坐标系中的点通过 Point 结构体表示,包含 x 和 y 两个整型成员:

cv::Point center(150, 200);
std::cout << "点坐标:X=" << center.x << ", Y=" << center.y << std::endl;

矩形区域定义

Rect 类支持两种初始化方式:左上角坐标+宽高,或两个对角点坐标:

cv::Rect box1(50, 60, 120, 80);  // 方式一:x, y, width, height
std::cout << "矩形参数:X=" << box1.x << " Y=" << box1.y 
          << " 宽=" << box1.width << " 高=" << box1.height << std::endl;

通道分离技术

使用 split() 函数可将多通道图像分解为独立单通道矩阵。处理大尺寸图像时建议先通过 resize() 缩放:

#include <opencv2/opencv.hpp>
#include <vector>

int main() {
    cv::Mat img = cv::imread("colorful.png");
    if (img.empty()) return -1;
    
    cv::Mat scaled;
    cv::resize(img, scaled, cv::Size(), 0.6, 0.6, cv::INTER_AREA);
    
    std::vector<cv::Mat> channels;
    cv::split(scaled, channels);
    
    cv::imshow("蓝色通道", channels[0]);
    cv::imshow("绿色通道", channels[1]);
    cv::imshow("红色通道", channels[2]);
    cv::waitKey(0);
    return 0;
}

色彩空间转换实践

OpenCV 提供 cvtColor() 函数实现不同色彩空间的转换,常见包括 BGR 转灰度、HSV、HLS 等:

#include <opencv2/opencv.hpp>

int main() {
    cv::Mat source = cv::imread("input.jpg");
    if (source.empty()) return -1;
    
    cv::Mat resized, gray, hsv, hls;
    cv::resize(source, resized, cv::Size(), 0.5, 0.5);
    
    cv::cvtColor(resized, gray, cv::COLOR_BGR2GRAY);
    cv::cvtColor(resized, hsv, cv::COLOR_BGR2HSV);
    cv::cvtColor(resized, hls, cv::COLOR_BGR2HLS);
    
    cv::imshow("灰度空间", gray);
    cv::imshow("HSV空间", hsv);
    cv::imshow("HLS空间", hls);
    cv::waitKey(0);
    return 0;
}

图像模糊处理

高斯模糊通过 GaussianBlur() 实现,内核尺寸必须为奇数,否则将触发运行时错误:

cv::Mat input = cv::imread("sharp.jpg");
cv::Mat blurred;
cv::GaussianBlur(input, blurred, cv::Size(5, 5), 7, 7);
cv::imshow("模糊效果", blurred);
cv::waitKey(0);

Canny 边缘检测应用

结合高斯模糊与 Canny 算法可有效提取图像轮廓。模糊预处理能减少噪声干扰,提升检测精度:

#include <opencv2/opencv.hpp>

int main() {
    cv::Mat original = cv::imread("scene.jpg");
    if (original.empty()) return -1;
    
    cv::Mat scaled, blur, edges;
    cv::resize(original, scaled, cv::Size(), 0.5, 0.5);
    cv::GaussianBlur(scaled, blur, cv::Size(3, 3), 5, 5);
    cv::Canny(blur, edges, 50, 150);
    
    cv::imshow("原始图像", scaled);
    cv::imshow("边缘检测结果", edges);
    cv::waitKey(0);
    return 0;
}

ROI 区域裁剪

通过定义矩形 ROI(感兴趣区域)可实现图像裁剪。Rect 参数前两位为左上角坐标,后两位为宽度和高度:

#include <opencv2/opencv.hpp>

int main() {
    cv::Mat original = cv::imread("landscape.jpg");
    cv::Mat resized = cv::imread("landscape.jpg");
    cv::resize(original, resized, cv::Size(), 0.4, 0.4);
    
    cv::Rect region(80, 90, 200, 180);
    cv::Mat cropped = resized(region);
    
    cv::imshow("完整图像", resized);
    cv::imshow("裁剪区域", cropped);
    cv::waitKey(0);
    return 0;
}

图形绘制功能

OpenCV 支持在图像上绘制圆形、矩形、直线及文本。创建画布时需指定颜色空间与初始颜色值:

#include <opencv2/opencv.hpp>

int main() {
    cv::Mat canvas(480, 640, CV_8UC3, cv::Scalar(30, 30, 30));
    
    cv::circle(canvas, cv::Point(320, 240), 80, cv::Scalar(0, 200, 0), 3);
    cv::rectangle(canvas, cv::Point(100, 150), cv::Point(250, 300), cv::Scalar(0, 0, 200), 2);
    cv::line(canvas, cv::Point(50, 50), cv::Point(590, 430), cv::Scalar(200, 200, 0), 4);
    cv::putText(canvas, "OpenCV Demo", cv::Point(200, 40), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(255, 255, 255), 2);
    
    cv::imshow("绘制结果", canvas);
    cv::waitKey(0);
    return 0;
}

透视变换实现

通过 getPerspectiveTransform() 计算变换矩阵,再使用 warpPerspective() 完成图像透视矫正:

#include <opencv2/opencv.hpp>

int main() {
    cv::Mat source = cv::imread("document.png");
    if (source.empty()) return -1;
    
    cv::Mat scaled, output;
    cv::resize(source, scaled, cv::Size(), 0.5, 0.5);
    
    const float targetW = 300, targetH = 400;
    cv::Point2f sourcePts[4] = {{50, 150}, {350, 100}, {80, 650}, {380, 600}};
    cv::Point2f destPts[4] = {{0, 0}, {targetW, 0}, {0, targetH}, {targetW, targetH}};
    
    cv::Mat transform = cv::getPerspectiveTransform(sourcePts, destPts);
    cv::warpPerspective(scaled, output, transform, cv::Size(targetW, targetH));
    
    cv::imshow("原始视角", scaled);
    cv::imshow("矫正结果", output);
    cv::waitKey(0);
    return 0;
}

变换效果示例如下:

透视变换效果

颜色阈值提取

利用 inRange() 函数可筛选特定颜色区间,生成二值掩膜。配合 HSV 色彩空间可提升颜色识别稳定性:

#include <opencv2/opencv.hpp>

int main() {
    cv::Mat source = cv::imread("object.jpg");
    cv::Mat resized, hsv, mask;
    cv::resize(source, resized, cv::Size(), 0.3, 0.3);
    cv::cvtColor(resized, hsv, cv::COLOR_BGR2HSV);
    
    cv::namedWindow("颜色调节");
    int hMin = 0, hMax = 20, sMin = 110, sMax = 240, vMin = 150, vMax = 250;
    cv::createTrackbar("H 最小", "颜色调节", &hMin, 179);
    cv::createTrackbar("H 最大", "颜色调节", &hMax, 179);
    cv::createTrackbar("S 最小", "颜色调节", &sMin, 255);
    cv::createTrackbar("S 最大", "颜色调节", &sMax, 255);
    cv::createTrackbar("V 最小", "颜色调节", &vMin, 255);
    cv::createTrackbar("V 最大", "颜色调节", &vMax, 255);
    
    while (true) {
        cv::Scalar lower(hMin, sMin, vMin);
        cv::Scalar upper(hMax, sMax, vMax);
        cv::inRange(hsv, lower, upper, mask);
        
        cv::imshow("原始图像", resized);
        cv::imshow("HSV 空间", hsv);
        cv::imshow("颜色掩膜", mask);
        if (cv::waitKey(10) == 27) break; // ESC 键退出
    }
    return 0;
}

调节效果示例如下:

颜色提取效果

轮廓检测流程

完整轮廓提取流程:灰度转换 → 高斯模糊 → Canny 边缘检测 → 形态学膨胀 → 轮廓查找与绘制:

#include <opencv2/opencv.hpp>
#include <vector>

void drawContours(cv::Mat& target, const cv::Mat& binary) {
    std::vector<std::vector<cv::Point>> contours;
    std::vector<cv::Vec4i> hierarchy;
    cv::findContours(binary, contours, hierarchy, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
    cv::drawContours(target, contours, -1, cv::Scalar(0, 255, 0), 2);
}

int main() {
    cv::Mat source = cv::imread("shapes.jpg");
    cv::Mat resized, gray, blurred, edges, dilated;
    cv::resize(source, resized, cv::Size(), 0.3, 0.3);
    
    cv::cvtColor(resized, gray, cv::COLOR_BGR2GRAY);
    cv::GaussianBlur(gray, blurred, cv::Size(3, 3), 3, 0);
    cv::Canny(blurred, edges, 25, 75);
    
    cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3));
    cv::dilate(edges, dilated, kernel);
    
    drawContours(resized, dilated);
    
    cv::imshow("轮廓检测结果", resized);
    cv::waitKey(0);
    return 0;
}

检测效果示例如下:

轮廓检测效果

人脸检测实现

基于 Haar 级联分类器的人脸检测需加载预训练模型文件,通过 detectMultiScale() 定位目标:

#include <opencv2/opencv.hpp>
#include <opencv2/objdetect.hpp>

int main() {
    cv::Mat img = cv::imread("group.jpg");
    cv::Mat resized;
    cv::resize(img, resized, cv::Size(), 0.3, 0.3);
    
    cv::CascadeClassifier faceDetector;
    faceDetector.load("haarcascade_frontalface_default.xml");
    if (faceDetector.empty()) {
        std::cerr << "分类器加载失败" << std::endl;
        return -1;
    }
    
    std::vector<cv::Rect> detectedFaces;
    faceDetector.detectMultiScale(resized, detectedFaces, 1.1, 3);
    
    for (const auto& face : detectedFaces) {
        cv::rectangle(resized, face.tl(), face.br(), cv::Scalar(0, 255, 0), 2);
    }
    
    cv::imshow("人脸检测结果", resized);
    cv::waitKey(0);
    return 0;
}

视频流颜色追踪

在视频序列中追踪特定颜色,需逐帧转换色彩空间并应用阈值筛选:

#include <opencv2/opencv.hpp>
#include <vector>

std::vector<std::vector<int>> colorRanges = {{68, 72, 156, 102, 126, 255}};
std::vector<cv::Scalar> trackColors = {{0, 255, 0}};

void processFrame(cv::Mat& frame) {
    cv::Mat hsvFrame;
    cv::cvtColor(frame, hsvFrame, cv::COLOR_BGR2HSV);
    
    for (size_t i = 0; i < colorRanges.size(); ++i) {
        cv::Mat colorMask;
        cv::Scalar lower(colorRanges[i][0], colorRanges[i][1], colorRanges[i][2]);
        cv::Scalar upper(colorRanges[i][3], colorRanges[i][4], colorRanges[i][5]);
        cv::inRange(hsvFrame, lower, upper, colorMask);
        cv::imshow("追踪掩膜 " + std::to_string(i), colorMask);
    }
}

int main() {
    cv::VideoCapture camera(0);
    if (!camera.isOpened()) return -1;
    
    cv::Mat frame;
    while (true) {
        camera >> frame;
        if (frame.empty()) break;
        
        processFrame(frame);
        cv::imshow("摄像头画面", frame);
        
        if (cv::waitKey(10) == 27) break;
    }
    
    camera.release();
    cv::destroyAllWindows();
    return 0;
}

视频文件读取

视频本质上是由连续帧图像构成,通过快速播放形成动态效果。使用 VideoCapture 类可逐帧读取:

#include <opencv2/opencv.hpp>

int main() {
    cv::VideoCapture video("clip.mp4");
    if (!video.isOpened()) {
        std::cerr << "视频打开失败" << std::endl;
        return -1;
    }
    
    cv::Mat frame;
    while (video.read(frame)) {
        cv::imshow("视频播放", frame);
        if (cv::waitKey(30) == 27) break; // 30ms 间隔,ESC 退出
    }
    
    video.release();
    return 0;
}

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。