opencv基础操作
- Ai
- 2天前
- 34热度
- 0评论
图像的读取和显示
读写图像
cv::Mat image = cv::imread("image.jpg", cv::IMREAD_COLOR);
使用imread函数读取图像,第一个参数是图像文件的路径,第二个参数是解释图像的颜色和格式(如彩色图像、灰度图像等)。第二个参数可省略,默认是cv::IMREAD_COLOR,以彩色图像读取。
cv::imwrite("output.jpg", image);
使用imwrite存储图像。
显示
使用imshow基于图像用户界面的显示方式,这种方式用于桌面的计算机,直接在屏幕上展示图像。
cv::imshow("Window title", image);
cv::waitKey(0); // 等待按键按下
通过/dev/fb0节点写入,这种方式一般应用在嵌入式平台上,写入屏幕的驱动中。
std::ofstream ofs("/dev/fb0");
cv::Mat framebuffer;
定义一个存储图像像素数据的容器
cv::cvtColor(frame, framebuffer, cv::COLOR_BGR2BGR565);
将图像格式进行转换为与驱动支持的格式BGR565
ofs.write(reinterpret_cast<char*>(framebuffer.ptr(0)), framebuffer.total() * framebuffer.elemSize());
//现将framebuffer强制转换为char*格式,确保内存数据按字节进行处理。
//framebuffer.total()返回的是像素总元素数量,如果framebuffer是多通道,那就返回总数
//framebuffer.elemSize()返回的是每个像素字节大小。
//需要注意的是使用一次性写入,要注意fb的位置,每次写需要重新定位
还有另外一种写法,每一行每一行的刷新
cv::Size2f frame_size = frame.size();
cv::cvtColor(frame, framebuffer_compat, cv::COLOR_BGR2BGR565);
for (int y = 0; y < frame_size.height; y++) {
ofs.seekp(y * framebuffer_width * 2);
//定位一行的位置,framebuffer_width是宽,即每行多少个像素
//*2是每个像素多少个字节,BGR565是2个字节。
ofs.write(reinterpret_cast<char*>(framebuffer_compat.ptr(y)), frame_size.width * 2);
//写入一行数据,一行的数据量为frame_size.width * 2
}
下面是封装的示例函数
void display_image(const cv::Mat& image, int framebuffer_width = 720)
{
static std::ofstream ofs("/dev/fb0");
if (!ofs) {
std::cerr << "Error: Could not open framebuffer device!" << std::endl;
return;
}
cv::Mat framebuffer;
if (image.channels() == 1) {
cv::cvtColor(image, framebuffer, cv::COLOR_GRAY2BGRA);
} else if (image.channels() == 3) {
cv::cvtColor(image, framebuffer, cv::COLOR_BGR2BGRA);
} else if (image.channels() == 4) {
image.copyTo(framebuffer);
} else {
std::cerr << "Error: Unsupported image format!" << std::endl;
return;
}
cv::Size2f frame_size = framebuffer.size();
if (frame_size.width > framebuffer_width) {
// 计算新的宽高,保持图像的纵横比
float aspect_ratio = frame_size.height / frame_size.width;
int newWidth = framebuffer_width;
int newHeight = static_cast<int>(newWidth * aspect_ratio);
// 调整图像大小
cv::Mat resizedImage;
cv::resize(framebuffer, resizedImage, cv::Size(newWidth, newHeight));
framebuffer = resizedImage;
frame_size = resizedImage.size();
}
for (int y = 0; y < frame_size.height; y++) {
ofs.seekp(y * framebuffer_width * 4);
ofs.write(reinterpret_cast<char*>(framebuffer.ptr(y)), frame_size.width * 4);
}
}
示例
int main()
{
cv::Mat test_image = cv::imread("test.jpg");
if (test_image.empty()) {
std::cerr << "Could not open the image" << std::endl;
return -1;
}
std::ofstream ofs("/dev/fb0");
if (!ofs.is_open()) {
std::cerr << "Failed to open framebuffer device." << std::endl;
return -1;
}
// 将 BGR 图像转换为 BGRA 格式(RGB8888)
cv::Mat framebuffer;
cv::cvtColor(test_image, framebuffer, cv::COLOR_BGR2BGRA);
ofs.write(reinterpret_cast<char*>(framebuffer.ptr(0)),
framebuffer.total() * framebuffer.elemSize());
return 0;
}
几何变换
这里的变换指的是缩放、旋转、平移、翻转。
裁剪与缩放
缩放
cv::Mat resizedImage;
cv::resize(image, resizedImage, cv::Size(newWidth, newHeight));
裁剪
Rect roi(100, 100, 200, 200); // (x, y, width, height)
//先于x,y坐标开始,再按照width,height定义一个矩形框。
Mat croppedImage = image(roi);
//将矩形框作用在image上,得到一个新的图像croppedImage
旋转
// cv::Point2f用于表示二维浮点坐标的类,下面是计算旋转中心点。
cv::Point2f center(image.cols / 2.0, image.rows / 2.0);
// 用于计算二维旋转的仿射变换矩阵,45是旋转角度,1.0是缩放比例。
cv::Mat rotationMatrix = cv::getRotationMatrix2D(center, 45.0, 1.0);
// 声明存储旋转后图像的变量
cv::Mat rotatedImage;
// 执行仿射变换进行图像旋转
cv::warpAffine(image, rotatedImage, rotationMatrix, image.size());
翻转
cv::Mat flippedImage;
cv::flip(image, flippedImage, 1); // 1表示水平翻转,0表示垂直翻转
颜色变换
图像的颜色空间包括RGB、灰度和HSV等。
- RGB:RGB是最常见的颜色空间,表示红、绿、蓝三个通道。
- 灰度:灰度图像只有一个通道,表示亮度。
- HSV:HSV颜色空间表示色调(Hue)、饱和度(Saturation)和亮度(Value)。
颜色空间转换
RGB转灰度
cv::Mat grayImage;
cv::cvtColor(image, grayImage, cv::COLOR_BGR2GRAY);
RGB转HSV
cv::Mat hsvImage;
cv::cvtColor(image, hsvImage, cv::COLOR_BGR2HSV);
RGB转RGB565
cv::Mat rgb565Image;
cv::cvtColor(rgb565Image, framebuffer, cv::COLOR_BGR2BGR565);
通道分离
这里的通道指的是图像通道比如RGB的R/G/B 3个通道。通道分离的场景是分析每个颜色通道的像素值,比如在检测红色物体时,可以单独分析红色通道。另外还可以用做图像增强,对不同通道应用不同的增强算法,然后再合并。
通道分离
std::vector<cv::Mat> channels; //分离出的通道存储到channels中
cv::split(image, channels);
通道合并
cv::Mat mergedImage;
cv::merge(channels, mergedImage);
示例代码
int main()
{
cv::Mat test_image = cv::imread("test.jpg");
if (test_image.empty()) {
std::cerr << "Could not open the image" << std::endl;
return -1;
}
double angle = 90;
// 计算旋转中心点
cv::Point2f center(test_image.cols / 2.0, test_image.rows / 2.0);
// 计算旋转矩阵
cv::Mat rotationMatrix = cv::getRotationMatrix2D(center, angle, 1.0);
// 声明存储旋转后图像的变量
cv::Mat rotatedImage;
// 执行仿射变换进行图像旋转
cv::warpAffine(test_image, rotatedImage, rotationMatrix, test_image.size());
std::ofstream ofs("/dev/fb0");
if (!ofs.is_open()) {
std::cerr << "Failed to open framebuffer device." << std::endl;
return -1;
}
// 将 BGR 图像转换为 BGRA 格式(RGB8888)
cv::Mat framebuffer;
cv::cvtColor(rotatedImage, framebuffer, cv::COLOR_BGR2BGRA);
ofs.write(reinterpret_cast<char*>(framebuffer.ptr(0)),
framebuffer.total() * framebuffer.elemSize());
return 0;
}
总结
本章节总结opencv操作常用的数据结构。
Mat
Mat对象的用途主要为存储图像、创建和操作多维矩阵。Mat数据类型分为两部分:信息头+指向像素数据的矩阵指针,信息头存储的是图像的尺寸、存储方法、存储地址。指向像素的矩阵指针为字面意思,即指向存储所有像素值的矩阵指针。
Mat A, C; //只创建信息头
A = imread(argv[1], IMREAD_COLOR); //为矩阵开辟内存空间。
Mat B(A); // Use the copy constructor
C = A; // Assignment operator
如果在读取图像的时候只想获取图像中的部分图像(感兴趣的区域ROI),可以使用Rect和Range来标中数据。
Mat D (A, Rect(10, 10, 100, 100) ); // using a rectangle
Mat E = A(Range::all(), Range(1,3)); // using row and column boundaries
其中Rect(10,10,100,100)前两位是坐标,后两位指定宽高,示例如下。
Range::all()选中所有的行,Range(1,3)选中1~3列。
Mat对象作为通用矩阵类和图像容器,容器中存储的是原始的像素值。在opencv中描述这些像素值有专门的数据格式。
Mat Img(640, 640, CV_8UC3);
上述中640*640大小的图像,存储的数据类型是CV_U8C3,这里的CV_U8C3格式为基本数据类型+通道数。"CV_"表示前缀,"8"表示每个像素值的位深比特数,有8/16/32/64bits,"U"表示数据类型为无符号,"C3"表示通道数RGB。关于通道一般有几种,示例如下:
- 1通道:灰度图像
- 3通道:RGB通道,图像由红、绿、蓝三色组成。
- 4通道:在RGB通道基础上,加一个透明通道。
Scalar
Scalar用于表示颜色或像素的值,他是一个模板类,存储了4个值,每个值代表图像的颜色通道,如BGR或HSV。
template<typename _Tp>
class Scalar_ {
public: _Tp val[4]; // 颜色值,最多支持四个通道
....
};
cv::Scalar(0, 0, 255); // 红色 BGR 颜色,表示 (蓝色 = 0, 绿色 = 0, 红色 = 255) cv::Scalar(255, 0, 0); // 蓝色 BGR 颜色,表示 (蓝色 = 255, 绿色 = 0, 红色 = 0) cv::Scalar(0, 255, 0); // 绿色 BGR 颜色,表示 (蓝色 = 0, 绿色 = 255, 红色 = 0)
cv::Scalar(0, 255, 0, 128); // 半透明绿色
cv::Scalar(255, 0, 0, 255); // 完全不透明的蓝色
Size
Size类用来表示图像的大小、矩阵的尺寸。
class Size {
public:
Size();
Size(int _width, int _height);
Size(double _width, double _height);
int width; // 图像宽度
int height; // 图像高度
};
下面是常用的用法。
设置图像的尺寸
cv::Mat image = cv::imread("image.jpg");
cv::Size new_size(800, 600); // 新的尺寸
cv::resize(image, image, new_size); // 将图像调整为新尺寸
获取图像的尺寸
cv::Mat image = cv::imread("image.jpg");
cv::Size image_size = image.size(); // 获取图像尺寸
创建一个尺寸大小的矩阵
cv::Mat mat(cv::Size(400, 300), CV_8UC1); // 创建一个大小为 400x300 的单通道图像
cvtColor
cvtColor用于颜色空间的转化,图像的颜色空间一般有RGB,BGR(RGB存储顺序的不同),HSV,Lab等,其可以将图像从一种颜色空间变换为另一种颜色空间。
cv::Mat cv::cvtColor(const cv::Mat& src, cv::Mat& dst, int code, int dstCn = 0);
- src: 输入图像
- dst:输出图像
- code:指定转化格式,如 cv::COLOR_BGR2GRAY,cv::COLOR_BGR2HSV。
- dstCn:输出通道数,如果是0,表示通道数与目标颜色空间通道匹配。
RGB转BGR
cv::Mat src = cv::imread("image.jpg"); // 读取 RGB 图像(如果图像是 RGB 格式的话)
cv::Mat bgr; cv::cvtColor(src, bgr, cv::COLOR_RGB2BGR); // 转换为 BGR 图像
HSB转BRG
cv::Mat hsv = cv::imread("image_hsv.jpg"); // 读取 HSV 图像
cv::Mat bgr; cv::cvtColor(hsv, bgr, cv::COLOR_HSV2BGR); // 转换为 BGR 图像
BRG转灰度
cv::Mat src = cv::imread("image.jpg"); // 读取 BGR 图像
cv::Mat gray; cv::cvtColor(src, gray, cv::COLOR_BGR2GRAY); // 转换为灰度图