【欢迎关注编码小哥,学习更多实用的编程方法和技巧】
一、常用的访问像素的方法
1、使用at()方法
cpp
// 灰度图
cv::Mat grayImage;
for (int y = 0; y < grayImage.rows; y++) {
for (int x = 0; x < grayImage.cols; x++) {
uchar pixel = grayImage.at<uchar>(y, x);
// 处理像素
grayImage.at<uchar>(y, x) = pixel + 10;
}
}
// 彩色图
cv::Mat colorImage;
for (int y = 0; y < colorImage.rows; y++) {
for (int x = 0; x < colorImage.cols; x++) {
cv::Vec3b pixel = colorImage.at<cv::Vec3b>(y, x);
// 处理像素
pixel[0] = pixel[0] + 10; // B通道
pixel[1] = pixel[1] + 10; // G通道
pixel[2] = pixel[2] + 10; // R通道
colorImage.at<cv::Vec3b>(y, x) = pixel;
}
}
2、使用指针遍历
cpp
// 灰度图
cv::Mat grayImage;
for (int y = 0; y < grayImage.rows; y++) {
uchar* row = grayImage.ptr<uchar>(y);
for (int x = 0; x < grayImage.cols; x++) {
row[x] = row[x] + 10;
}
}
// 彩色图
cv::Mat colorImage;
for (int y = 0; y < colorImage.rows; y++) {
cv::Vec3b* row = colorImage.ptr<cv::Vec3b>(y);
for (int x = 0; x < colorImage.cols; x++) {
row[x][0] = row[x][0] + 10; // B通道
row[x][1] = row[x][1] + 10; // G通道
row[x][2] = row[x][2] + 10; // R通道
}
}
3、迭代器遍历
cpp
// 灰度图
cv::Mat grayImage;
cv::MatIterator_<uchar> it, end;
for (it = grayImage.begin<uchar>(), end = grayImage.end<uchar>(); it != end; ++it) {
*it = *it + 10;
}
// 彩色图
cv::Mat colorImage;
cv::MatIterator_<cv::Vec3b> it, end;
for (it = colorImage.begin<cv::Vec3b>(), end = colorImage.end<cv::Vec3b>(); it != end; ++it) {
(*it)[0] = (*it)[0] + 10; // B通道
(*it)[1] = (*it)[1] + 10; // G通道
(*it)[2] = (*it)[2] + 10; // R通道
}
4、forEach()方法(C++11)
cpp
// 灰度图
cv::Mat grayImage;
grayImage.forEach<uchar>([](uchar &pixel, const int * position) {
pixel = pixel + 10;
});
// 彩色图
cv::Mat colorImage;
colorImage.forEach<cv::Vec3b>([](cv::Vec3b &pixel, const int * position) {
pixel[0] = pixel[0] + 10; // B通道
pixel[1] = pixel[1] + 10; // G通道
pixel[2] = pixel[2] + 10; // R通道
});
二、基于image.data直接访问像素数据方法
1、数据访问基础
cpp
// 获取图像基本信息
int width = image.cols;
int height = image.rows;
int channels = image.channels();
uchar* pixelPtr = image.data;
2、灰度图像访问
cpp
cv::Mat grayImage;
for (int y = 0; y < grayImage.rows; y++) {
for (int x = 0; x < grayImage.cols; x++) {
// 直接通过data指针访问
uchar* pixel = grayImage.data + y * grayImage.step + x;
*pixel = *pixel + 10; // 像素处理
}
}
3、彩色图像访问
cpp
cv::Mat colorImage;
for (int y = 0; y < colorImage.rows; y++) {
for (int x = 0; x < colorImage.cols; x++) {
// 计算像素位置
int index = y * colorImage.step + x * colorImage.channels();
// BGR通道
uchar blue = colorImage.data[index];
uchar green = colorImage.data[index + 1];
uchar red = colorImage.data[index + 2];
// 修改像素
colorImage.data[index] = blue + 10;
colorImage.data[index + 1] = green + 10;
colorImage.data[index + 2] = red + 10;
}
}
4、通用像素访问模板
cpp
template<typename T>
void processImage(cv::Mat& image) {
int channels = image.channels();
for (int y = 0; y < image.rows; y++) {
for (int x = 0; x < image.cols; x++) {
// 计算像素起始位置
int index = y * image.step + x * channels;
// 根据通道数处理
if (channels == 1) {
T& pixel = reinterpret_cast<T&>(image.data[index]);
pixel = pixel + 10;
} else if (channels == 3) {
T* pixel = reinterpret_cast<T*>(&image.data[index]);
pixel[0] = pixel[0] + 10; // B
pixel[1] = pixel[1] + 10; // G
pixel[2] = pixel[2] + 10; // R
}
}
}
}
// 使用示例
cv::Mat grayImage(height, width, CV_8UC1);
cv::Mat colorImage(height, width, CV_8UC3);
processImage<uchar>(grayImage);
processImage<uchar>(colorImage);
5、高级数据访问
cpp
class ImageProcessor {
private:
cv::Mat image;
uchar* data;
int width, height, channels, step;
public:
ImageProcessor(cv::Mat& img) : image(img) {
data = image.data;
width = image.cols;
height = image.rows;
channels = image.channels();
step = image.step;
}
// 安全的像素访问
uchar& pixel(int x, int y, int channel = 0) {
return data[y * step + x * channels + channel];
}
// 像素处理
void process() {
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
// 处理每个通道
for (int c = 0; c < channels; c++) {
uchar& p = pixel(x, y, c);
p = cv::saturate_cast<uchar>(p * 1.2);
}
}
}
}
};
// 使用
cv::Mat image = cv::imread("image.jpg");
ImageProcessor processor(image);
processor.process();
三、像素算术运算
1、基本像素算术运算
cpp
// 像素加法
cv::Mat result = image1 + image2;
// 像素减法
cv::Mat result = image1 - image2;
// 像素乘法
cv::Mat result = image1.mul(image2);
// 像素除法
cv::Mat result = image1 / image2;
2、标量运算
cpp
// 对整个图像进行标量运算
cv::Mat brightened = image + 50; // 增加亮度
cv::Mat darkened = image - 50; // 降低亮度
cv::Mat increased_contrast = image * 1.5; // 增加对比度
cv::Mat decreased_contrast = image * 0.5; // 降低对比度
3、像素逐元素运算
cpp
// 自定义像素运算函数
cv::Mat pixelWiseOperation(const cv::Mat& src) {
cv::Mat dst = src.clone();
// 遍历每个像素
for (int y = 0; y < dst.rows; y++) {
for (int x = 0; x < dst.cols; x++) {
// 灰度图
if (dst.channels() == 1) {
uchar& pixel = dst.at<uchar>(y, x);
pixel = cv::saturate_cast<uchar>(std::pow(pixel, 1.2));
}
// 彩色图
else if (dst.channels() == 3) {
cv::Vec3b& pixel = dst.at<cv::Vec3b>(y, x);
pixel[0] = cv::saturate_cast<uchar>(std::pow(pixel[0], 1.2));
pixel[1] = cv::saturate_cast<uchar>(std::pow(pixel[1], 1.2));
pixel[2] = cv::saturate_cast<uchar>(std::pow(pixel[2], 1.2));
}
}
}
return dst;
}
4、通道分离与运算
cpp
// 分离通道并对特定通道进行运算
cv::Mat performChannelOperation(const cv::Mat& src) {
std::vector<cv::Mat> channels;
cv::split(src, channels);
// 对蓝色通道进行操作
channels[0] = channels[0] * 1.5;
cv::Mat result;
cv::merge(channels, result);
return result;
}
5、安全像素运算模板
cpp
template<typename T>
cv::Mat safePixelOperation(const cv::Mat& src, double factor) {
cv::Mat dst = src.clone();
for (int y = 0; y < dst.rows; y++) {
for (int x = 0; x < dst.cols; x++) {
if (dst.channels() == 1) {
T& pixel = dst.at<T>(y, x);
pixel = cv::saturate_cast<T>(pixel * factor);
}
else if (dst.channels() == 3) {
T* pixel = dst.at<T>(y, x);
pixel[0] = cv::saturate_cast<T>(pixel[0] * factor);
pixel[1] = cv::saturate_cast<T>(pixel[1] * factor);
pixel[2] = cv::saturate_cast<T>(pixel[2] * factor);
}
}
}
return dst;
}
// 使用示例
cv::Mat result8U = safePixelOperation<uchar>(image, 1.5);
cv::Mat result16U = safePixelOperation<ushort>(image16, 1.5);
6、复杂像素运算
cpp
// 多图像混合
cv::Mat blendImages(const cv::Mat& img1, const cv::Mat& img2, double alpha = 0.5) {
cv::Mat blended;
cv::addWeighted(img1, alpha, img2, 1 - alpha, 0, blended);
return blended;
}
// 图像映射变换
cv::Mat gammaCorrection(const cv::Mat& src, double gamma = 1.0) {
cv::Mat dst;
src.convertTo(dst, CV_32F, 1.0/255);
cv::pow(dst, gamma, dst);
dst = dst * 255;
dst.convertTo(dst, CV_8U);
return dst;
}
7、位运算
cpp
// 位运算
cv::Mat bitwiseOperations(const cv::Mat& src) {
cv::Mat mask = src > 128; // 创建二值化掩膜
cv::Mat result1, result2;
cv::bitwise_and(src, mask, result1); // 与运算
cv::bitwise_or(src, mask, result2); // 或运算
return result1;
}
8、高级像素映射
cpp
// 自定义像素映射
cv::Mat customPixelMapping(const cv::Mat& src) {
cv::Mat lookupTable(1, 256, CV_8U);
uchar* lut = lookupTable.ptr();
// 创建查找表
for (int i = 0; i < 256; i++) {
lut[i] = cv::saturate_cast<uchar>(std::sin(i * CV_PI / 255.0) * 255.0);
}
cv::Mat result;
cv::LUT(src, lookupTable, result);
return result;
}
注意事项
- 使用
cv::saturate_cast
防止溢出 - 注意数据类型转换
- 考虑图像通道数
- 处理边界情况
- 性能优化
性能建议
- 使用
cv::Mat
操作替代逐像素遍历 - 利用OpenCV的矩阵运算
- 对于大图像,考虑并行处理
- 使用
cv::cuda
进行GPU加速