OpenCV 基础图像处理核心操作详解
图像通道解析
数字图像的色彩信息通常由多个通道叠加构成。对于标准彩色图像,一般采用红、绿、蓝三通道模型。通过 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;
}