OpenCV基础操作与图像处理
目录
一、基础操作
1. 图像的基本操作
1.1 读取、显示和保存图像
1.2 图像的基本属性
1.3 图像的创建与初始化
1.4 图像的像素操作
2. 图像的几何变换
2.1 缩放、旋转、平移、翻转
2.2 仿射变换与透视变换
3.图像的颜色空间转换
3.1 RGB、灰度、HSV等颜色空间
3.2 颜色空间转换
3.3 通道分离与合并
4. 实例
4.1 图像的读取与显示
4.2 图像的保存
4.3 获取图像属性
4.4 访问和修改像素值
4.5 图像颜色空间转换
4.6 图像的裁剪与缩放
4.7 图像的复制与克隆
4.8 图像的几何变换
二、图像处理
1. 图像滤波
1.1 均值滤波
1.2 高斯滤波
1.3 中值滤波
1.4 自定义滤波器
2. 图像边缘检测
2.1 Sobel算子
2.2 Canny 边缘检测
3. 图像形态学操作
3.1 腐蚀
3.2 膨胀
3.3 开运算
3.4 闭运算
形态学梯度
4. 图像阈值化
4.1 二值化
4.2 自适应阈值
4.3 Otsu阈值法
5. 图像直方图
5.1 计算直方图
5.2 直方图均衡化
5.3 直方图对比
6. 实例
6.1 图像滤波
6.2 边缘检测
6.3 图像阈值化
6.4 形态学操作
6.5 轮廓检测
一、基础操作
1. 图像的基本操作
1.1 读取、显示和保存图像
在 OpenCV 中,图像的基本操作包括读取、显示和保存图像。这些操作是图像处理的基础。
读取图像:使用imread
函数读取图像。该函数的第一个参数是图像文件的路径,第二个参数是读取图像的方式(如彩色图像、灰度图像等)。
cv::Mat image = cv::imread("image.jpg", cv::IMREAD_COLOR);
显示图像:使用imshow
函数显示图像。该函数的第一个参数是窗口的名称,第二个参数是要显示的图像。
cv::imshow("Display Window", image);
cv::waitKey(0); // 等待按键按下
保存图像:使用imwrite
函数保存图像。该函数的第一个参数是保存文件的路径,第二个参数是要保存的图像。
cv::imwrite("output.jpg", image);
1.2 图像的基本属性
图像的基本属性包括尺寸、通道数和像素值。
尺寸:图像的尺寸可以通过rows
和cols
属性获取。
int height = image.rows;
int width = image.cols;
通道数:图像的通道数可以通过channels()
方法获取。
int channels = image.channels();
像素值:可以通过at
方法访问图像的像素值。
cv::Vec3b pixel = image.at<cv::Vec3b>(y, x); // 访问(x, y)处的像素值
1.3 图像的创建与初始化
可以通过Mat
类创建和初始化图像。
创建图像:可以创建一个指定大小和类型的图像。
cv::Mat newImage(480, 640, CV_8UC3, cv::Scalar(0, 0, 255)); // 创建一个640x480的红色图像
初始化图像:可以使用setTo
方法初始化图像。
image.setTo(cv::Scalar(255, 255, 255)); // 将图像初始化为白色
1.4 图像的像素操作
图像的像素操作包括遍历像素和修改像素值。
遍历像素:可以使用双重循环遍历图像的每个像素。
for (int y = 0; y < image.rows; y++) {for (int x = 0; x < image.cols; x++) {cv::Vec3b& pixel = image.at<cv::Vec3b>(y, x);// 对像素进行操作}
}
修改像素值:可以直接修改像素的值。
pixel[0] = 255; // 将蓝色通道设置为255
pixel[1] = 0; // 将绿色通道设置为0
pixel[2] = 0; // 将红色通道设置为0
2. 图像的几何变换
2.1 缩放、旋转、平移、翻转
图像的几何变换包括缩放、旋转、平移和翻转。
缩放:使用resize
函数缩放图像。
cv::Mat resizedImage;
cv::resize(image, resizedImage, cv::Size(newWidth, newHeight));
旋转:使用getRotationMatrix2D
和warpAffine
函数旋转图像。
cv::Point2f center(image.cols / 2.0, image.rows / 2.0);
cv::Mat rotationMatrix = cv::getRotationMatrix2D(center, angle, 1.0);
cv::Mat rotatedImage;
cv::warpAffine(image, rotatedImage, rotationMatrix, image.size());
平移:使用warpAffine
函数平移图像。
cv::Mat translationMatrix = (cv::Mat_<double>(2, 3) << 1, 0, tx, 0, 1, ty);
cv::Mat translatedImage;
cv::warpAffine(image, translatedImage, translationMatrix, image.size());
翻转:使用flip
函数翻转图像。
cv::Mat flippedImage;
cv::flip(image, flippedImage, 1); // 1表示水平翻转,0表示垂直翻转
2.2 仿射变换与透视变换
仿射变换:仿射变换是线性变换加上平移,可以使用warpAffine
函数实现。
cv::Mat affineMatrix = cv::getAffineTransform(srcPoints, dstPoints);
cv::Mat affineImage;
cv::warpAffine(image, affineImage, affineMatrix, image.size());
透视变换:透视变换是更一般的变换,可以使用warpPerspective
函数实现。
cv::Mat perspectiveMatrix = cv::getPerspectiveTransform(srcPoints, dstPoints);
cv::Mat perspectiveImage;
cv::warpPerspective(image, perspectiveImage, perspectiveMatrix, image.size());
3.图像的颜色空间转换
3.1 RGB、灰度、HSV等颜色空间
图像的颜色空间包括RGB、灰度和HSV等。
- RGB:RGB是最常见的颜色空间,表示红、绿、蓝三个通道。
- 灰度:灰度图像只有一个通道,表示亮度。
- HSV:HSV颜色空间表示色调(Hue)、饱和度(Saturation)和亮度(Value)。
3.2 颜色空间转换
使用 cvtColor
函数进行颜色空间转换。
RGB 转灰度:
cv::Mat grayImage;
cv::cvtColor(image, grayImage, cv::COLOR_BGR2GRAY);
RGB转HSV:
cv::Mat hsvImage;
cv::cvtColor(image, hsvImage, cv::COLOR_BGR2HSV);
3.3 通道分离与合并
通道分离:使用split
函数将图像的通道分离。
std::vector<cv::Mat> channels;
cv::split(image, channels);
通道合并:使用merge
函数将多个通道合并为一个图像。
cv::Mat mergedImage;
cv::merge(channels, mergedImage);
4. 实例
C++ OpenCV 的基础操作包括图像的读取、显示、保存、像素操作、图像属性获取等。以下是一些常见的 OpenCV 基础操作及其代码示例:
4.1 图像的读取与显示
#include <opencv2/opencv.hpp>
#include <iostream>using namespace cv;
using namespace std;int main() {// 读取图像Mat image = imread("test.jpg");// 检查图像是否成功加载if (image.empty()) {cout << "错误:无法加载图像,请检查路径是否正确。" << endl;return -1;}// 显示图像namedWindow("Display Image", WINDOW_AUTOSIZE);imshow("Display Image", image);// 等待按键waitKey(0);// 关闭窗口destroyAllWindows();return 0;
}
4.2 图像的保存
#include <opencv2/opencv.hpp>
#include <iostream>using namespace cv;
using namespace std;int main() {// 读取图像Mat image = imread("test.jpg");if (image.empty()) {cout << "错误:无法加载图像,请检查路径是否正确。" << endl;return -1;}// 保存图像bool isSaved = imwrite("saved_image.jpg", image);if (isSaved) {cout << "图像保存成功!" << endl;} else {cout << "图像保存失败!" << endl;}return 0;
}
4.3 获取图像属性
#include <opencv2/opencv.hpp>
#include <iostream>using namespace cv;
using namespace std;int main() {// 读取图像Mat image = imread("test.jpg");if (image.empty()) {cout << "错误:无法加载图像,请检查路径是否正确。" << endl;return -1;}// 获取图像属性int width = image.cols; // 图像宽度int height = image.rows; // 图像高度int channels = image.channels(); // 图像通道数cout << "图像宽度: " << width << endl;cout << "图像高度: " << height << endl;cout << "图像通道数: " << channels << endl;return 0;
}
4.4 访问和修改像素值
#include <opencv2/opencv.hpp>
#include <iostream>using namespace cv;
using namespace std;int main() {// 读取图像Mat image = imread("test.jpg");if (image.empty()) {cout << "错误:无法加载图像,请检查路径是否正确。" << endl;return -1;}// 访问像素值(BGR格式)Vec3b pixel = image.at<Vec3b>(100, 100); // 获取(100, 100)位置的像素值cout << "B: " << (int)pixel[0] << ", G: " << (int)pixel[1] << ", R: " << (int)pixel[2] << endl;// 修改像素值image.at<Vec3b>(100, 100) = Vec3b(255, 0, 0); // 将(100, 100)位置的像素设置为蓝色// 显示修改后的图像imshow("Modified Image", image);waitKey(0);destroyAllWindows();return 0;
}
4.5 图像颜色空间转换
#include <opencv2/opencv.hpp>
#include <iostream>using namespace cv;
using namespace std;int main() {// 读取图像Mat image = imread("test.jpg");if (image.empty()) {cout << "错误:无法加载图像,请检查路径是否正确。" << endl;return -1;}// 转换为灰度图像Mat grayImage;cvtColor(image, grayImage, COLOR_BGR2GRAY);// 显示灰度图像imshow("Gray Image", grayImage);waitKey(0);destroyAllWindows();return 0;
}
4.6 图像的裁剪与缩放
#include <opencv2/opencv.hpp>
#include <iostream>using namespace cv;
using namespace std;int main() {// 读取图像Mat image = imread("test.jpg");if (image.empty()) {cout << "错误:无法加载图像,请检查路径是否正确。" << endl;return -1;}// 裁剪图像Rect roi(100, 100, 200, 200); // (x, y, width, height)Mat croppedImage = image(roi);// 缩放图像Mat resizedImage;resize(image, resizedImage, Size(400, 400)); // 缩放到400x400// 显示裁剪和缩放后的图像imshow("Cropped Image", croppedImage);imshow("Resized Image", resizedImage);waitKey(0);destroyAllWindows();return 0;
}
4.7 图像的复制与克隆
#include <opencv2/opencv.hpp>
#include <iostream>using namespace cv;
using namespace std;int main() {// 读取图像Mat image = imread("test.jpg");if (image.empty()) {cout << "错误:无法加载图像,请检查路径是否正确。" << endl;return -1;}// 复制图像Mat copiedImage = image.clone();// 修改复制的图像circle(copiedImage, Point(100, 100), 50, Scalar(0, 255, 0), 2); // 在复制的图像上画一个圆// 显示原始图像和修改后的图像imshow("Original Image", image);imshow("Copied Image", copiedImage);waitKey(0);destroyAllWindows();return 0;
}
4.8 图像的几何变换
#include <opencv2/opencv.hpp>
#include <iostream>using namespace cv;
using namespace std;int main() {// 读取图像Mat image = imread("test.jpg");if (image.empty()) {cout << "错误:无法加载图像,请检查路径是否正确。" << endl;return -1;}// 旋转图像Mat rotatedImage;Point2f center(image.cols / 2, image.rows / 2); // 旋转中心double angle = 45; // 旋转角度double scale = 1.0; // 缩放比例Mat rotationMatrix = getRotationMatrix2D(center, angle, scale);warpAffine(image, rotatedImage, rotationMatrix, image.size());// 显示旋转后的图像imshow("Rotated Image", rotatedImage);waitKey(0);destroyAllWindows();return 0;
}
二、图像处理
1. 图像滤波
图像滤波是图像处理中的一种基本操作,主要用于去除图像中的噪声或增强图像的某些特征。常见的滤波方法包括均值滤波、高斯滤波、中值滤波以及自定义滤波器。
1.1 均值滤波
均值滤波是一种简单的线性滤波方法,它将图像中每个像素的值替换为其邻域内所有像素值的平均值。这种方法可以有效去除噪声,但也会使图像变得模糊。
cv::Mat src = cv::imread("image.jpg", cv::IMREAD_GRAYSCALE);
cv::Mat dst;
cv::blur(src, dst, cv::Size(3, 3)); // 3x3的均值滤波
1.2 高斯滤波
高斯滤波是一种非线性滤波方法,它使用高斯函数来计算邻域内像素的权重,从而对图像进行平滑处理。高斯滤波在去除噪声的同时,能够更好地保留图像的边缘信息。
cv::GaussianBlur(src, dst, cv::Size(5, 5), 0); // 5x5的高斯滤波
1.3 中值滤波
中值滤波是一种非线性滤波方法,它将图像中每个像素的值替换为其邻域内所有像素值的中值。这种方法在去除椒盐噪声时效果非常好。
cv::medianBlur(src, dst, 5); // 5x5的中值滤波
1.4 自定义滤波器
OpenCV允许用户自定义滤波器核,通过cv::filter2D
函数可以实现自定义滤波操作。
cv::Mat kernel = (cv::Mat_<float>(3, 3) << 1, 0, -1, 0, 0, 0, -1, 0, 1);
cv::filter2D(src, dst, -1, kernel);
2. 图像边缘检测
边缘检测是图像处理中的一个重要任务,用于识别图像中物体的边界。常用的边缘检测方法包括Sobel算子和Canny边缘检测。
2.1 Sobel算子
Sobel算子是一种基于梯度的边缘检测方法,它可以检测图像中的水平和垂直边缘。
cv::Mat grad_x, grad_y;
cv::Sobel(src, grad_x, CV_16S, 1, 0); // 水平方向
cv::Sobel(src, grad_y, CV_16S, 0, 1); // 垂直方向
cv::convertScaleAbs(grad_x, grad_x);
cv::convertScaleAbs(grad_y, grad_y);
cv::addWeighted(grad_x, 0.5, grad_y, 0.5, 0, dst); // 合并结果
2.2 Canny 边缘检测
Canny 边缘检测是一种多阶段的边缘检测算法,它能够有效地检测出图像中的边缘,并且对噪声具有较强的鲁棒性。
cv::Canny(src, dst, 100, 200); // 阈值1=100,阈值2=200
3. 图像形态学操作
形态学操作是基于图像形状的一系列操作,常用于图像的前景和背景分离、噪声去除等任务。常见的形态学操作包括腐蚀、膨胀、开运算、闭运算和形态学梯度。
3.1 腐蚀
腐蚀操作可以消除图像中的小物体或细节,使得前景物体变小。
cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3));
cv::erode(src, dst, kernel);
3.2 膨胀
膨胀操作可以扩大图像中的前景物体,常用于填补前景物体中的空洞。
cv::dilate(src, dst, kernel);
3.3 开运算
开运算是先腐蚀后膨胀的操作,常用于去除小物体或噪声。
cv::morphologyEx(src, dst, cv::MORPH_OPEN, kernel);
3.4 闭运算
闭运算是先膨胀后腐蚀的操作,常用于填补前景物体中的小孔。
cv::morphologyEx(src, dst, cv::MORPH_CLOSE, kernel);
形态学梯度
形态学梯度是膨胀和腐蚀的差值,可以用于提取物体的边缘。
cv::morphologyEx(src, dst, cv::MORPH_GRADIENT, kernel);
4. 图像阈值化
图像阈值化是将图像转换为二值图像的过程,常用于图像分割。常见的阈值化方法包括二值化、自适应阈值和Otsu阈值法。
4.1 二值化
二值化是将图像中的像素值根据设定的阈值分为两类,通常用于简单的图像分割。
cv::threshold(src, dst, 127, 255, cv::THRESH_BINARY);
4.2 自适应阈值
自适应阈值根据图像的局部区域动态计算阈值,适用于光照不均匀的图像。
cv::adaptiveThreshold(src, dst, 255, cv::ADAPTIVE_THRESH_MEAN_C, cv::THRESH_BINARY, 11, 2);
4.3 Otsu阈值法
Otsu阈值法是一种自动确定阈值的方法,适用于双峰直方图的图像。
cv::threshold(src, dst, 0, 255, cv::THRESH_BINARY | cv::THRESH_OTSU);
5. 图像直方图
直方图是图像处理中用于分析图像亮度分布的工具。常见的直方图操作包括计算直方图、直方图均衡化和直方图对比。
5.1 计算直方图
直方图可以反映图像中像素值的分布情况。
cv::Mat hist;
int histSize = 256;
float range[] = {0, 256};
const float* histRange = {range};
cv::calcHist(&src, 1, 0, cv::Mat(), hist, 1, &histSize, &histRange);
5.2 直方图均衡化
直方图均衡化可以增强图像的对比度,使得图像的亮度分布更加均匀。
cv::equalizeHist(src, dst);
5.3 直方图对比
直方图对比可以用于比较两幅图像的相似性。
double compare = cv::compareHist(hist1, hist2, cv::HISTCMP_CORREL);
6. 实例
OpenCV 中常见的图像处理操作,包括滤波、边缘检测、阈值化、形态学操作和轮廓检测。通过这些技术,你可以实现更复杂的图像处理任务。以下是 C++ OpenCV 中常见的图像处理操作及其代码示例:
6.1 图像滤波
图像滤波用于去除噪声或增强图像特征。
均值滤波
#include <opencv2/opencv.hpp>
#include <iostream>using namespace cv;
using namespace std;int main() {Mat image = imread("test.jpg");if (image.empty()) {cout << "错误:无法加载图像,请检查路径是否正确。" << endl;return -1;}// 均值滤波Mat blurredImage;blur(image, blurredImage, Size(5, 5)); // 5x5 的核imshow("Original Image", image);imshow("Blurred Image", blurredImage);waitKey(0);destroyAllWindows();return 0;
}
高斯滤波
#include <opencv2/opencv.hpp>
#include <iostream>using namespace cv;
using namespace std;int main() {Mat image = imread("test.jpg");if (image.empty()) {cout << "错误:无法加载图像,请检查路径是否正确。" << endl;return -1;}// 高斯滤波Mat gaussianBlurredImage;GaussianBlur(image, gaussianBlurredImage, Size(5, 5), 0); // 5x5 的核imshow("Original Image", image);imshow("Gaussian Blurred Image", gaussianBlurredImage);waitKey(0);destroyAllWindows();return 0;
}
中值滤波
#include <opencv2/opencv.hpp>
#include <iostream>using namespace cv;
using namespace std;int main() {Mat image = imread("test.jpg");if (image.empty()) {cout << "错误:无法加载图像,请检查路径是否正确。" << endl;return -1;}// 中值滤波Mat medianBlurredImage;medianBlur(image, medianBlurredImage, 5); // 核大小为 5imshow("Original Image", image);imshow("Median Blurred Image", medianBlurredImage);waitKey(0);destroyAllWindows();return 0;
}
6.2 边缘检测
边缘检测用于提取图像中的边缘信息。
Canny 边缘检测
#include <opencv2/opencv.hpp>
#include <iostream>using namespace cv;
using namespace std;int main() {Mat image = imread("test.jpg");if (image.empty()) {cout << "错误:无法加载图像,请检查路径是否正确。" << endl;return -1;}// 转换为灰度图像Mat grayImage;cvtColor(image, grayImage, COLOR_BGR2GRAY);// Canny 边缘检测Mat edges;Canny(grayImage, edges, 100, 200); // 阈值1和阈值2imshow("Original Image", image);imshow("Canny Edges", edges);waitKey(0);destroyAllWindows();return 0;
}
6.3 图像阈值化
阈值化用于将图像转换为二值图像。
简单阈值化
#include <opencv2/opencv.hpp>
#include <iostream>using namespace cv;
using namespace std;int main() {Mat image = imread("test.jpg");if (image.empty()) {cout << "错误:无法加载图像,请检查路径是否正确。" << endl;return -1;}// 转换为灰度图像Mat grayImage;cvtColor(image, grayImage, COLOR_BGR2GRAY);// 简单阈值化Mat binaryImage;threshold(grayImage, binaryImage, 127, 255, THRESH_BINARY);imshow("Original Image", image);imshow("Binary Image", binaryImage);waitKey(0);destroyAllWindows();return 0;
}
自适应阈值化
#include <opencv2/opencv.hpp>
#include <iostream>using namespace cv;
using namespace std;int main() {Mat image = imread("test.jpg");if (image.empty()) {cout << "错误:无法加载图像,请检查路径是否正确。" << endl;return -1;}// 转换为灰度图像Mat grayImage;cvtColor(image, grayImage, COLOR_BGR2GRAY);// 自适应阈值化Mat adaptiveBinaryImage;adaptiveThreshold(grayImage, adaptiveBinaryImage, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 11, 2);imshow("Original Image", image);imshow("Adaptive Binary Image", adaptiveBinaryImage);waitKey(0);destroyAllWindows();return 0;
}
6.4 形态学操作
形态学操作用于处理图像的形状和结构。
腐蚀与膨胀
#include <opencv2/opencv.hpp>
#include <iostream>using namespace cv;
using namespace std;int main() {Mat image = imread("test.jpg");if (image.empty()) {cout << "错误:无法加载图像,请检查路径是否正确。" << endl;return -1;}// 转换为灰度图像Mat grayImage;cvtColor(image, grayImage, COLOR_BGR2GRAY);// 二值化Mat binaryImage;threshold(grayImage, binaryImage, 127, 255, THRESH_BINARY);// 腐蚀操作Mat erodedImage;Mat kernel = getStructuringElement(MORPH_RECT, Size(5, 5));erode(binaryImage, erodedImage, kernel);// 膨胀操作Mat dilatedImage;dilate(binaryImage, dilatedImage, kernel);imshow("Original Image", image);imshow("Eroded Image", erodedImage);imshow("Dilated Image", dilatedImage);waitKey(0);destroyAllWindows();return 0;
}
6.5 轮廓检测
轮廓检测用于提取图像中的对象轮廓。
#include <opencv2/opencv.hpp>
#include <iostream>using namespace cv;
using namespace std;int main() {Mat image = imread("test.jpg");if (image.empty()) {cout << "错误:无法加载图像,请检查路径是否正确。" << endl;return -1;}// 转换为灰度图像Mat grayImage;cvtColor(image, grayImage, COLOR_BGR2GRAY);// 二值化Mat binaryImage;threshold(grayImage, binaryImage, 127, 255, THRESH_BINARY);// 查找轮廓vector<vector<Point>> contours;vector<Vec4i> hierarchy;findContours(binaryImage, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE);// 绘制轮廓Mat contourImage = Mat::zeros(image.size(), CV_8UC3);for (size_t i = 0; i < contours.size(); i++) {drawContours(contourImage, contours, i, Scalar(0, 255, 0), 2);}imshow("Original Image", image);imshow("Contours", contourImage);waitKey(0);destroyAllWindows();return 0;
}