当前位置: 首页 > news >正文

c/c++的opencv的图像预处理讲解

OpenCV 图像预处理核心技术详解 (C/C++)

图像预处理是计算机视觉任务中至关重要的一步。原始图像往往受到噪声、光照不均、尺寸不一等多种因素的影响,直接用于后续分析(如特征提取、目标检测、机器学习模型训练等)可能会导致性能下降或结果不准确。预处理旨在通过一系列操作来增强图像质量、去除噪声、标准化图像数据,使其更适合特定应用。

本文将详细介绍几种 OpenCV 中常用的图像预处理技术,包括其 C/C++ 实现、关键参数解析以及使用时的注意事项。


目录

  1. 灰度转换 (Grayscale Conversion)
  2. 图像缩放 (Resizing)
  3. 图像平滑/模糊 (Smoothing/Blurring)
    • 高斯模糊 (Gaussian Blur)
    • 中值模糊 (Median Blur)
    • 双边滤波 (Bilateral Filter)
  4. 阈值化处理 (Thresholding)
    • 简单阈值 (Simple Thresholding)
    • 自适应阈值 (Adaptive Thresholding)
  5. 图像归一化 (Normalization)
  6. 形态学操作 (Morphological Operations)
    • 腐蚀 (Erosion) 与膨胀 (Dilation)
    • 开运算 (Opening) 与闭运算 (Closing)
  7. 直方图均衡化 (Histogram Equalization)
  8. 总结与建议

1. 灰度转换 (Grayscale Conversion)

将彩色图像转换为灰度图像是最常见的预处理步骤之一。

  • 目的:降低数据维度(从3通道变为1通道),减少计算量,某些算法(如Canny边缘检测)通常在灰度图上操作。
  • OpenCV 函数cv::cvtColor()
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc.hpp> // 包含 cvtColorint main() {cv::Mat src = cv::imread("input.jpg", cv::IMREAD_COLOR);if (src.empty()) {std::cerr << "Error: Image cannot be loaded!" << std::endl;return -1;}cv::Mat gray;cv::cvtColor(src, gray, cv::COLOR_BGR2GRAY); // 注意OpenCV默认加载为BGRcv::imshow("Original", src);cv::imshow("Grayscale", gray);cv::waitKey(0);cv::destroyAllWindows();return 0;
}

参数解析 (cv::cvtColor):

  • src: 输入图像 (彩色图像)。
  • dst: 输出图像 (灰度图像)。
  • code: 颜色空间转换代码。
    • cv::COLOR_BGR2GRAY: 从 BGR (OpenCV 默认的彩色图像通道顺序) 转换为灰度。
    • cv::COLOR_RGB2GRAY: 从 RGB 转换为灰度 (如果你的图像源是 RGB)。
    • cv::COLOR_BGR2HSV: 转换为 HSV 颜色空间等。

注意事项:

  • 确保输入图像确实是彩色图像。对已经是灰度的图像进行此操作通常不会报错,但无意义。
  • OpenCV 使用 cv::imread() 加载图像时,默认通道顺序是 BGR。如果你的图像数据来自其他源(例如某些库或传感器可能输出 RGB),请注意选择正确的转换代码。

2. 图像缩放 (Resizing)

调整图像的尺寸以满足特定算法的输入要求或减少计算量。

  • 目的:统一输入尺寸,构建图像金字塔,加速处理。
  • OpenCV 函数cv::resize()
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc.hpp> // 包含 resizeint main() {cv::Mat src = cv::imread("input.jpg");if (src.empty()) {std::cerr << "Error: Image cannot be loaded!" << std::endl;return -1;}cv::Mat resized_abs, resized_rel;cv::Size new_size(300, 200); // 目标绝对尺寸:宽300, 高200// 方法1: 指定目标尺寸cv::resize(src, resized_abs, new_size, 0, 0, cv::INTER_LINEAR);// 方法2: 指定缩放因子double scale_x = 0.5;double scale_y = 0.5;cv::resize(src, resized_rel, cv::Size(), scale_x, scale_y, cv::INTER_LINEAR);cv::imshow("Original", src);cv::imshow("Resized (Absolute)", resized_abs);cv::imshow("Resized (Relative)", resized_rel);cv::waitKey(0);cv::destroyAllWindows();return 0;
}

参数解析 (cv::resize):

  • src: 输入图像。
  • dst: 输出图像。
  • dsize: 输出图像的目标尺寸 (cv::Size(width, height))。如果设置为 cv::Size() (即 cv::Size(0,0)),则尺寸将通过 fxfy 计算。
  • fx: 沿水平轴的缩放因子。如果 dsize 非零,则此参数无效。
  • fy: 沿垂直轴的缩放因子。如果 dsize 非零,则此参数无效。
  • interpolation: 插值方法。
    • cv::INTER_NEAREST: 最近邻插值。速度最快,但效果可能较差,有马赛克感。
    • cv::INTER_LINEAR: 双线性插值 (默认)。速度和效果的良好折中,常用于放大。
    • cv::INTER_CUBIC: 双三次插值。效果较好,尤其在放大时,但计算量更大。
    • cv::INTER_AREA: 基于区域的重采样。在缩小图像时效果较好,可以避免波纹。放大时类似最近邻。
    • cv::INTER_LANCZOS4: Lanczos 插值 (8x8邻域)。效果最好,但计算量最大。

注意事项:

  • 插值方法选择:
    • 缩小图像时,cv::INTER_AREA 通常是最佳选择,以避免信息丢失和摩尔纹。
    • 放大图像时,cv::INTER_LINEAR 是一个不错的起点,cv::INTER_CUBICcv::INTER_LANCZOS4 可以提供更好的质量,但更慢。
  • 长宽比: 如果只指定 dsize 而不考虑原始长宽比,图像可能会变形。如果需要保持长宽比,应先计算一个轴的缩放因子或新尺寸,然后据此计算另一个。
  • 如果同时提供了 dsize (非零) 和 fx/fy (非零),dsize 优先。

3. 图像平滑/模糊 (Smoothing/Blurring)

用于减少图像噪声,平滑图像细节。

高斯模糊 (Gaussian Blur)

使用高斯核对图像进行卷积,有效去除高斯噪声。

  • OpenCV 函数cv::GaussianBlur()
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc.hpp>int main() {cv::Mat src = cv::imread("input_noisy.jpg"); // 假设有一张带噪声的图if (src.empty()) { /* ... error handling ... */ return -1; }cv::Mat blurred_gaussian;cv::Size kernel_size(5, 5); // 高斯核尺寸,必须是正奇数double sigmaX = 0; // X方向标准差,若为0,则由ksize.width计算// double sigmaY = 0; // Y方向标准差,若为0,则由ksize.height计算 (或等于sigmaX)cv::GaussianBlur(src, blurred_gaussian, kernel_size, sigmaX);cv::imshow("Original", src);cv::imshow("Gaussian Blurred", blurred_gaussian);cv::waitKey(0);cv::destroyAllWindows();return 0;
}

参数解析 (cv::GaussianBlur):

  • ksize: 高斯核的尺寸 (cv::Size(width, height))。宽度和高度必须是正奇数,也可以不同。
  • sigmaX: X 方向的高斯核标准差。
  • sigmaY: Y 方向的高斯核标准差。如果为0,则设置成与 sigmaX 相同;如果两者都为0,则它们从 ksize.widthksize.height 计算得出。建议将 sigmaY 设为0,让其自动等于 sigmaX 或根据 ksize 计算。
  • borderType: 边界处理方式,默认 cv::BORDER_DEFAULT

注意事项 (GaussianBlur):

  • ksize 越大,图像越模糊。sigmaX (和 sigmaY) 越大,模糊程度也越大。
  • 如果 sigmaX (和 sigmaY) 设置得非常小,而 ksize 较大,效果可能不佳。通常让 sigma 根据 ksize 计算 (通过将 sigmaX 设为0) 是个好主意,或者根据经验值设定。
  • 高斯模糊对所有方向的平滑程度相同,可能会模糊掉一些有用的边缘信息。

中值模糊 (Median Blur)

用像素邻域内的中值替换该像素的值,对椒盐噪声特别有效。

  • OpenCV 函数cv::medianBlur()
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc.hpp>int main() {cv::Mat src = cv::imread("salt_pepper_noise.jpg"); // 假设有椒盐噪声图if (src.empty()) { /* ... error handling ... */ return -1; }cv::Mat blurred_median;int ksize_median = 5; // 孔径线性尺寸,必须是大于1的奇数cv::medianBlur(src, blurred_median, ksize_median);cv::imshow("Original", src);cv::imshow("Median Blurred", blurred_median);cv::waitKey(0);cv::destroyAllWindows();return 0;
}

参数解析 (cv::medianBlur):

  • ksize: 孔径的线性尺寸 (例如,5 表示 5x5 的邻域)。必须是大于1的奇数。

注意事项 (medianBlur):

  • ksize 越大,平滑效果越强,但也可能丢失更多图像细节。
  • 相比高斯模糊,中值模糊在去除椒盐噪声的同时能更好地保留边缘。
  • 计算开销随 ksize 增加而显著增加。

双边滤波 (Bilateral Filter)

在平滑图像的同时保持边缘清晰。

  • OpenCV 函数cv::bilateralFilter()
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc.hpp>int main() {cv::Mat src = cv::imread("input.jpg");if (src.empty()) { /* ... error handling ... */ return -1; }cv::Mat blurred_bilateral;int d = 9;              // 滤波期间每个像素邻域的直径。如果非正,则从 sigmaSpace 计算。double sigmaColor = 75; // 颜色空间滤波器的 Sigma 值。较大值意味着邻域内更远的颜色也会混合在一起,从而产生更大区域的半相等颜色。double sigmaSpace = 75; // 坐标空间滤波器的 Sigma 值。较大值意味着更远的像素将相互影响,只要它们的颜色足够接近。当 d>0 时,它指定邻域大小而不考虑 sigmaSpace。否则,d 与 sigmaSpace 成正比。cv::bilateralFilter(src, blurred_bilateral, d, sigmaColor, sigmaSpace);cv::imshow("Original", src);cv::imshow("Bilateral Filtered", blurred_bilateral);cv::waitKey(0);cv::destroyAllWindows();return 0;
}

参数解析 (cv::bilateralFilter):

  • d: 在过滤期间使用的每个像素邻域的直径。如果为非正数(例如 -1),则会从 sigmaSpace 计算出来。通常取 5 到 9 之间的值。
  • sigmaColor: 颜色空间的标准差。值越大,意味着越多差异较大的颜色会被认为是相似的,从而被平均。
  • sigmaSpace: 坐标空间的标准差。值越大,意味着越远的像素会相互影响(只要颜色相似)。如果 d > 0,则 d 指定邻域大小,sigmaSpace 不起作用;否则 dsigmaSpace 成正比。

注意事项 (bilateralFilter):

  • 双边滤波比其他模糊方法慢得多。
  • 参数 sigmaColorsigmaSpace 的调整对结果影响很大,需要根据具体图像和需求进行调试。
  • 如果 sigmaColor 值过大,效果接近高斯模糊;如果过小,则平滑效果不明显。
  • 如果 sigmaSpace 值过大,计算量会增加。

4. 阈值化处理 (Thresholding)

将图像转换为二值图像(通常是黑白)。

简单阈值 (Simple Thresholding)

将像素值与固定阈值进行比较。

  • OpenCV 函数cv::threshold()
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc.hpp>int main() {cv::Mat src = cv::imread("input.jpg", cv::IMREAD_GRAYSCALE); // 阈值处理通常在灰度图上进行if (src.empty()) { /* ... error handling ... */ return -1; }cv::Mat thresh_binary, thresh_otsu;double thresh_val = 127;double max_val = 255;// 基本二值阈值cv::threshold(src, thresh_binary, thresh_val, max_val, cv::THRESH_BINARY);// Otsu's 二值化 (自动计算阈值)// 此时,输入的 thresh_val (这里是0) 被忽略,函数会自动计算最佳阈值double otsu_thresh = cv::threshold(src, thresh_otsu, 0, max_val, cv::THRESH_BINARY | cv::THRESH_OTSU);std::cout << "Otsu's calculated threshold: " << otsu_thresh << std::endl;cv::imshow("Original Grayscale", src);cv::imshow("Binary Threshold", thresh_binary);cv::imshow("Otsu's Threshold", thresh_otsu);cv::waitKey(0);cv::destroyAllWindows();return 0;
}

参数解析 (cv::threshold):

  • src: 输入图像,通常是单通道灰度图。
  • dst: 输出的二值图像。
  • thresh: 阈值。
  • maxval: 当像素值超过(或满足某些条件,取决于 type)阈值时赋予的新值。
  • type: 阈值类型:
    • cv::THRESH_BINARY: 如果 src(x,y) > thresh,则 dst(x,y) = maxval,否则 dst(x,y) = 0
    • cv::THRESH_BINARY_INV: cv::THRESH_BINARY 的反转。
    • cv::THRESH_TRUNC: 如果 src(x,y) > thresh,则 dst(x,y) = thresh,否则 dst(x,y) = src(x,y)
    • cv::THRESH_TOZERO: 如果 src(x,y) > thresh,则 dst(x,y) = src(x,y),否则 dst(x,y) = 0
    • cv::THRESH_TOZERO_INV: cv::THRESH_TOZERO 的反转。
    • cv::THRESH_OTSU: Otsu’s 二值化。与上述类型之一(通常是 cv::THRESH_BINARY)通过 | (位或) 组合使用。函数会自动计算一个全局最优阈值。此时 thresh 参数被忽略。
    • cv::THRESH_TRIANGLE: Triangle 算法,也用于自动阈值确定。

注意事项 (threshold):

  • 输入图像应为灰度图。
  • cv::THRESH_OTSUcv::THRESH_TRIANGLE 对于双峰直方图的图像效果较好,可以自动找到合适的阈值,但对光照不均的图像可能效果不佳。
  • 选择合适的 thresh 值对于简单阈值至关重要,通常需要实验或基于图像直方图分析。

自适应阈值 (Adaptive Thresholding)

对于光照不均的图像,使用局部阈值而非全局阈值。

  • OpenCV 函数cv::adaptiveThreshold()
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc.hpp>int main() {cv::Mat src = cv::imread("uneven_lighting.jpg", cv::IMREAD_GRAYSCALE); // 假设光照不均if (src.empty()) { /* ... error handling ... */ return -1; }cv::Mat adaptive_thresh_mean, adaptive_thresh_gaussian;double max_val = 255;int block_size = 11; // 邻域大小,必须是奇数double C = 2;        // 从均值或加权均值中减去的常数cv::adaptiveThreshold(src, adaptive_thresh_mean, max_val,cv::ADAPTIVE_THRESH_MEAN_C, cv::THRESH_BINARY,block_size, C);cv::adaptiveThreshold(src, adaptive_thresh_gaussian, max_val,cv::ADAPTIVE_THRESH_GAUSSIAN_C, cv::THRESH_BINARY,block_size, C);cv::imshow("Original Grayscale", src);cv::imshow("Adaptive Mean Threshold", adaptive_thresh_mean);cv::imshow("Adaptive Gaussian Threshold", adaptive_thresh_gaussian);cv::waitKey(0);cv::destroyAllWindows();return 0;
}

参数解析 (cv::adaptiveThreshold):

  • src: 输入灰度图像。
  • dst: 输出二值图像。
  • maxValue: 赋予超过阈值的像素的新值。
  • adaptiveMethod: 自适应阈值算法:
    • cv::ADAPTIVE_THRESH_MEAN_C: 阈值是邻域的均值减去 C
    • cv::ADAPTIVE_THRESH_GAUSSIAN_C: 阈值是邻域的高斯加权和减去 C
  • thresholdType: 阈值类型,通常是 cv::THRESH_BINARYcv::THRESH_BINARY_INV
  • blockSize: 用于计算阈值的像素邻域大小,必须是奇数。
  • C: 从均值或加权均值中减去的常数。可以是正数、零或负数。

注意事项 (adaptiveThreshold):

  • blockSizeC 的选择对结果影响很大,需要仔细调整。
  • blockSize 越大,参与计算局部阈值的区域就越大,细节可能会丢失。太小则可能对噪声敏感。
  • cv::ADAPTIVE_THRESH_GAUSSIAN_C 通常比 cv::ADAPTIVE_THRESH_MEAN_C 效果更好,因为它对中心点附近的像素赋予更大权重。

5. 图像归一化 (Normalization)

将像素值缩放到特定范围,例如 [0, 1] 或 [0, 255]。

  • 目的:消除由于光照和对比度不同带来的影响,改善某些算法(如机器学习模型)的性能。
  • OpenCV 函数cv::normalize()
#include <opencv2/opencv.hpp>
#include <opencv2/core.hpp> // 包含 normalizeint main() {// 假设我们有一个CV_32F类型的图像(例如,某些算法的输出)cv::Mat src = cv::Mat::zeros(100, 100, CV_32FC1);cv::randu(src, cv::Scalar::all(50), cv::Scalar::all(200)); // 填充50-200之间的随机值cv::Mat normalized_img;double alpha = 0;   // 归一化后的最小值double beta = 255;  // 归一化后的最大值 (对于显示,通常是255)// 对于机器学习特征,可能是1.0// 归一化到 [alpha, beta] 范围cv::normalize(src, normalized_img, alpha, beta, cv::NORM_MINMAX, CV_8UC1); // 输出为CV_8UC1用于显示// 如果只是想归一化到 [0,1] 并且保持浮点类型cv::Mat normalized_float;cv::normalize(src, normalized_float, 0.0, 1.0, cv::NORM_MINMAX, CV_32FC1);// 显示需要转换到8位cv::Mat src_display, norm_display;if (src.type() != CV_8U) src.convertTo(src_display, CV_8U, 255.0/(200-50), -50.0 * 255.0/(200-50)); // 手动调整范围以便显示else src.copyTo(src_display);normalized_img.copyTo(norm_display); // normalized_img 已经是 CV_8UC1cv::imshow("Original (scaled for display)", src_display);cv::imshow("Normalized to [0, 255]", norm_display);cv::waitKey(0);cv::destroyAllWindows();return 0;
}

参数解析 (cv::normalize):

  • src: 输入数组。
  • dst: 输出数组,与 src 大小相同。
  • alpha: 范围归一化的下界。
  • beta: 范围归一化的上界 (对于 cv::NORM_MINMAX) 或范数值 (对于其他类型)。
  • norm_type: 归一化类型:
    • cv::NORM_MINMAX: 将值线性缩放到 [alpha, beta] 范围。
    • cv::NORM_INF, cv::NORM_L1, cv::NORM_L2: 按指定范数进行归一化 (通常 beta 用作目标范数值)。
  • dtype: 当为负数时,输出数组 dst 的类型与 src 相同;否则,它与 src 的通道数相同,但深度为 dtype。例如,可以将 CV_32F 归一化为 CV_8U。
  • mask: 可选的操作掩码。

注意事项 (normalize):

  • 最常用的归一化类型是 cv::NORM_MINMAX
  • 如果 dtype 设置为输出特定类型(如 CV_8U),则会进行类型转换和可能的截断/缩放。
  • 在进行某些特征描述子计算或将图像输入到神经网络之前,归一化非常重要。

6. 形态学操作 (Morphological Operations)

基于形状改变图像结构的非线性操作,常用于噪声去除、物体分离/连接、寻找区域等。

  • 核心元素: 结构元素 (Kernel/Structuring Element),它定义了操作的邻域形状。
    • 使用 cv::getStructuringElement(shape, ksize, anchor) 创建。
      • shape: cv::MORPH_RECT (矩形), cv::MORPH_ELLIPSE (椭圆), cv::MORPH_CROSS (十字形)。
      • ksize: 结构元素的尺寸。
      • anchor: 锚点位置,默认在中心。

腐蚀 (Erosion) 与膨胀 (Dilation)

  • 腐蚀 (cv::erode): “收缩” 或 “细化” 图像中的亮区(前景)。去除小的噪点。
  • 膨胀 (cv::dilate): “扩张” 或 “加粗” 图像中的亮区。连接断开的部分,填充孔洞。
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc.hpp>int main() {cv::Mat src = cv::imread("binary_image.png", cv::IMREAD_GRAYSCALE); // 最好是二值图或灰度图if (src.empty()) { /* ... error handling ... */ return -1; }// 确保是二值图像 (例如,经过阈值化处理)cv::threshold(src, src, 127, 255, cv::THRESH_BINARY);cv::Mat eroded, dilated;cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(5, 5));// int iterations = 1; // 操作迭代次数cv::erode(src, eroded, kernel);cv::dilate(src, dilated, kernel);cv::imshow("Original Binary", src);cv::imshow("Eroded", eroded);cv::imshow("Dilated", dilated);cv::waitKey(0);cv::destroyAllWindows();return 0;
}

参数解析 (cv::erode, cv::dilate):

  • src: 输入图像。
  • dst: 输出图像。
  • kernel: 结构元素。如果为 cv::Mat(),则使用 3x3 矩形核。
  • anchor: 锚点位置,默认 cv::Point(-1,-1) 表示在核中心。
  • iterations: 操作迭代次数。次数越多,效果越明显。
  • borderType, borderValue: 边界处理。

开运算 (Opening) 与闭运算 (Closing)

通过组合腐蚀和膨胀实现更复杂的操作。使用 cv::morphologyEx()

  • 开运算 (cv::MORPH_OPEN): 先腐蚀后膨胀。用于去除小的噪点(暗背景上的亮噪点),平滑物体轮廓,断开细小连接。
  • 闭运算 (cv::MORPH_CLOSE): 先膨胀后腐蚀。用于填充物体内的小孔洞,连接邻近物体,平滑轮廓。
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc.hpp>int main() {cv::Mat src = cv::imread("noisy_binary.png", cv::IMREAD_GRAYSCALE);if (src.empty()) { /* ... error handling ... */ return -1; }cv::threshold(src, src, 127, 255, cv::THRESH_BINARY);cv::Mat opened, closed;cv::Mat kernel = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(7, 7));cv::morphologyEx(src, opened, cv::MORPH_OPEN, kernel);cv::morphologyEx(src, closed, cv::MORPH_CLOSE, kernel);cv::imshow("Original Binary", src);cv::imshow("Opened", opened);cv::imshow("Closed", closed);cv::waitKey(0);cv::destroyAllWindows();return 0;
}

参数解析 (cv::morphologyEx):

  • op: 形态学操作类型:
    • cv::MORPH_OPEN, cv::MORPH_CLOSE
    • cv::MORPH_GRADIENT: 膨胀图与腐蚀图之差,可得到物体轮廓。
    • cv::MORPH_TOPHAT: 原图与开运算结果之差。
    • cv::MORPH_BLACKHAT: 闭运算结果与原图之差。
  • 其他参数与 erode/dilate 类似。

注意事项 (形态学操作):

  • 通常在二值图像上操作效果最直观,但也可用于灰度图像。
  • 结构元素 kernel 的形状和大小对结果影响极大。矩形核适用于处理具有水平和垂直边缘的结构;椭圆或圆形核更通用。
  • iterations 参数可以增强效果,但多次小核操作不完全等同于一次大核操作。

7. 直方图均衡化 (Histogram Equalization)

增强图像对比度,尤其对那些像素值集中在某个狭窄范围内的图像有效。

  • 目的:扩展图像的像素强度分布,使其更均匀地覆盖整个强度范围。
  • OpenCV 函数:
    • cv::equalizeHist(): 全局直方图均衡化。
    • cv::CLAHE: 对比度受限的自适应直方图均衡化 (Contrast Limited Adaptive Histogram Equalization)。
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc.hpp>int main() {cv::Mat src = cv::imread("low_contrast.jpg", cv::IMREAD_GRAYSCALE); // 假设低对比度图if (src.empty()) { /* ... error handling ... */ return -1; }cv::Mat equalized_global;cv::equalizeHist(src, equalized_global);cv::Mat equalized_clahe;// 创建 CLAHE 对象// double clipLimit = 2.0; // 对比度限制阈值// cv::Size tileGridSize(8, 8); // 将图像划分为的小块数量cv::Ptr<cv::CLAHE> clahe = cv::createCLAHE();clahe->setClipLimit(2.0);clahe->setTileGridSize(cv::Size(8, 8));clahe->apply(src, equalized_clahe);cv::imshow("Original Grayscale", src);cv::imshow("Global Histogram Equalization", equalized_global);cv::imshow("CLAHE", equalized_clahe);cv::waitKey(0);cv::destroyAllWindows();return 0;
}

参数解析:

  • cv::equalizeHist(src, dst):

    • src: 输入8位单通道图像 (灰度图)。
    • dst: 输出均衡化后的图像。
  • cv::createCLAHE(clipLimit, tileGridSize):

    • clipLimit: 对比度限制。较高的值允许更大的对比度。如果噪声是问题,可以减小它。默认40.0。
    • tileGridSize: 将图像分割成的小块(tile)的网格尺寸。例如 cv::Size(8,8) 表示 8x8 的小块。在每个小块内进行直方图均衡化。

注意事项:

  • cv::equalizeHist() 是全局操作,可能会导致某些区域的对比度过度增强,并放大噪声。
  • CLAHE 是局部操作,将图像分成小块,在每个小块内进行直方图均衡化,然后通过双线性插值拼接,通常效果更好,能有效限制对比度放大,减少噪声。
  • CLAHEclipLimittileGridSize 参数需要根据图像内容调整。
  • 这些操作通常用于灰度图像。若要用于彩色图像,可以先转换到如 HSV 或 Lab 等颜色空间,对亮度通道 (V 或 L) 进行均衡化,然后再转换回 BGR。

8. 总结与建议

图像预处理是一个实验性很强的过程,没有万能的方法。

  • 理解你的数据: 分析图像的特点(噪声类型、光照条件、尺寸变化等)。
  • 明确你的目标: 预处理的目的是服务于后续任务。不同的任务可能需要不同的预处理组合。
  • 参数调整: 大多数预处理函数的参数对结果影响显著,需要耐心调试和比较。
  • 顺序问题: 预处理步骤的顺序也很重要。例如,通常先去噪再进行边缘检测或阈值化。
  • 可视化: 始终可视化每一步预处理的结果,以便直观判断效果。
  • 适度原则: 过度的预处理可能会丢失有用信息。

从这些基础操作开始,你可以构建复杂的预处理流水线来应对各种计算机视觉挑战。祝你在 OpenCV 的学习和应用中取得成功!


相关文章:

c/c++的opencv的图像预处理讲解

OpenCV 图像预处理核心技术详解 (C/C) 图像预处理是计算机视觉任务中至关重要的一步。原始图像往往受到噪声、光照不均、尺寸不一等多种因素的影响&#xff0c;直接用于后续分析&#xff08;如特征提取、目标检测、机器学习模型训练等&#xff09;可能会导致性能下降或结果不准…...

索恩格汽车SEG Automotive EDI 需求分析

SEG Automotive&#xff08;索恩格汽车&#xff09;是一家全球领先的汽车电气化系统供应商&#xff0c;专注于为传统内燃机和新能源车辆提供高效、可持续的动力解决方案。 EDI 在汽车行业的重要性 在汽车制造行业&#xff0c;高效的供应链是精益生产的核心。精益生产强调“按…...

【简单模拟实现list】

在C标准模板库&#xff08;STL&#xff09;中&#xff0c;list是一个非常强大的容器&#xff0c;它基于双向链表实现&#xff0c;支持高效的插入和删除操作。虽然我们可以直接使用STL中的list&#xff0c;但通过自己模拟实现一个list&#xff0c;可以更好地理解其背后的原理和数…...

深入解析ZAB协议:ZooKeeper的分布式一致性核心

引言 在分布式系统中&#xff0c;如何高效、可靠地实现多节点间的数据一致性是核心挑战之一。ZAB协议&#xff08;ZooKeeper Atomic Broadcast&#xff09;作为 ZooKeeper的核心算法&#xff0c;被广泛应用于分布式协调服务&#xff08;如Kafka、HBase、Dubbo等&#xff09;。…...

交叉熵损失函数,KL散度, Focal loss

交叉熵损失函数&#xff08;Cross-Entropy Loss&#xff09; 交叉熵损失函数&#xff0c;涉及两个概念&#xff0c;一个是损失函数&#xff0c;一个是交叉熵。 首先&#xff0c;对于损失函数。在机器学习中&#xff0c;损失函数就是用来衡量我们模型的预测结果与真实结果之间…...

k8s部署实战-springboot应用部署

在 Kubernetes 上部署 SpringBoot 应用实战指南 前言 本文将详细介绍如何将一个 SpringBoot 应用部署到 Kubernetes 集群中,包括制作镜像、编写部署文件、创建服务等完整步骤。 准备工作 1. 示例 SpringBoot 应用 假设我们有一个简单的 SpringBoot 应用,提供 REST API 服…...

快速选择算法:优化大数据中的 Top-K 问题

在处理海量数据时&#xff0c;经常会遇到这样的需求&#xff1a;找出数据中最大的前 K 个数&#xff0c;而不必对整个数据集进行排序。这种场景下&#xff0c;快速选择算法&#xff08;Quickselect&#xff09;就成了一个非常高效的解决方案。本文将通过一个 C 实现的快速选择算…...

uniapp-商城-60-后台 新增商品(属性的选中和页面显示)

前面添加了属性&#xff0c;添加属性的子级项目。也分析了如何回显&#xff0c;但是在添加新的商品的时&#xff0c;我们也同样需要进行选择&#xff0c;还要能正常的显示在界面上。下面对页面的显示进行分析。 1、界面情况回顾 属性显示其实是个一嵌套的数据显示。 2、选中的…...

利用 Amazon Bedrock Data Automation(BDA)对视频数据进行自动化处理与检索

当前点播视频平台搜索功能主要是基于视频标题的关键字检索。对于点播平台而言&#xff0c;我们希望可以通过优化视频搜索体验满足用户通过模糊描述查找视频的需求&#xff0c;从而提高用户的搜索体验。借助 Amazon Bedrock Data Automation&#xff08;BDA&#xff09;技术&…...

项目QT+ffmpeg+rtsp(一)——Qt的安装和rtsp的测试

文章目录 一、Qt安装二、插件配置tool与卸载三、下载ffmpeg四、查看能否使用(视频)五、代码复现5.1 rtsp申请5.2 rtsp在线测试5.3代码修改六、结果一、Qt安装 对于QT中5.12版本之后,都是使用在线版本,如果你想安装某一个的历史在线版本,一定要点击archive,不然显示不出来…...

高速光耦在通信行业的应用(五) | 5Mbps通信光耦的特性

针对5MBd速率光耦市场&#xff0c;晶台推出KL2200、KL2201和KL2202系列光耦 ,对标大部分国外品牌产品的应用&#xff1b;它分别由一个红外发射二极管和一个高速集成光电检测器逻辑门组成。 它采用 8 引脚 DIP 封装&#xff0c;并提供 SMD 选项。KL2200 的检测器具有一个三态输出…...

#跟着若城学鸿蒙# web篇-运动和方向传感器监测

前言 有些前端业务场景需要用到一些传感器&#xff0c;比如运动传感器和方向传感器来实现摇一摇功能。这就需要前端能够直接获取到相关数据&#xff0c;而不是通过 js 调用客户端代码来实现。 权限 还是需要在模块的module.json5文件中添加相关权限 {"name" : &qu…...

【匹配】Hirschberg

Hirschberg 文章目录 Hirschberg1. 算法介绍2. 公式及原理3. 伪代码 1. 算法介绍 背景与目标 Hirschberg 算法由 Dan Hirschberg 于1975年提出&#xff0c;是对 Needleman–Wunsch 全局比对的内存优化&#xff0c;通过分治策略将空间复杂度从 O ( m n ) O(mn) O(mn) 降到 O (…...

如何在 Windows 上安装类似 Synaptic 的 Chocolatey GUI 包管理器

如果你正在寻找类似 Linux 中 APT 的 Windows 包管理器&#xff0c;那么没有什么比 Chocolatey 更好的了。它是 Windows 10 上可用的最佳包管理器之一&#xff0c;可以通过命令行界面安装所有流行的软件和工具。然而&#xff0c;这并不意味着如果你不喜欢命令行&#xff0c;你就…...

激活函数全解析:定义、分类与 17 种常用函数详解

一、激活函数的定义与作用 定义&#xff1a; 激活函数是添加到人工神经网络中的函数&#xff0c;用于帮助网络学习数据中的复杂模式&#xff0c;决定神经元的输出。 核心作用&#xff1a; 为神经网络引入非线性&#xff0c;增强模型表达能力。需可微分&#xff08;或近似可微&…...

1-10 目录树

在ZIP归档文件中&#xff0c;保留着所有压缩文件和目录的相对路径和名称。当使用WinZIP等GUI软件打开ZIP归档文件时&#xff0c;可以从这些信息中重建目录的树状结构。请编写程序实现目录的树状结构的重建工作。 输入格式: 输入首先给出正整数N&#xff08;≤104&#xff09;…...

Python OOP核心技巧:如何正确选择实例方法、类方法和静态方法

Python方法类型全解析&#xff1a;实例方法、类方法与静态方法的使用场景 一、三种方法的基本区别二、访问能力对比表三、何时使用实例方法使用实例方法的核心场景&#xff1a;具体应用场景&#xff1a;1. 操作实例属性2. 对象间交互3. 实现特定实例的行为 四、何时使用类方法使…...

RK3588 ADB使用

安卓adb操作介绍 adb&#xff08;Android Debug Bridge&#xff09;是一个用于与安卓设备进行通信和控制的工具。adb可以通过USB或无线网络连接安卓设备&#xff0c;执行各种命令&#xff0c;如安装和卸载应用&#xff0c;传输文件&#xff0c;查看日志&#xff0c;运行shell命…...

ubuntu环境下 基于Python 打包的 批量命令行可视化操作工具 GUI

文章目录 一.需求&#xff1a;二.原理支撑&#xff1a;三.简单Demo四.封装成GUI1.依赖库2.代码 五.打包成可执行文件六.命令行的配置七.运行效果 一.需求&#xff1a; 作为测试工程师&#xff0c;为了到现场高效的调试&#xff0c;部署工作&#xff0c;需要一个可视化的工具&a…...

大语言模型 10 - 从0开始训练GPT 0.25B参数量 补充知识之模型架构 MoE、ReLU、FFN、MixFFN

写在前面 GPT&#xff08;Generative Pre-trained Transformer&#xff09;是目前最广泛应用的大语言模型架构之一&#xff0c;其强大的自然语言理解与生成能力背后&#xff0c;是一个庞大而精细的训练流程。本文将从宏观到微观&#xff0c;系统讲解GPT的训练过程&#xff0c;…...

SkyWalking的工作原理和搭建过程

SkyWalking 是一个开源的 应用性能监控系统&#xff08;APM&#xff09;&#xff0c;专为云原生、微服务架构设计。其核心原理基于 分布式追踪&#xff08;Distributed Tracing&#xff09;、指标收集&#xff08;Metrics Collection&#xff09; 和 日志关联&#xff08;Log C…...

CMS(plone / joomla 搭建测试)

开源选择 wordpress 用得最多 也是最容易有漏洞被攻击 被挂木马的 joomla &#xff08;JMS多站点&#xff1a;商业扩展&#xff09; — 多站点需付费 Drupal ProcessWire Plone因其内置的强大安全特性和较少的用户基础&#xff08;相比 WordPress 和 Joomla&#xff09;&#…...

基于 Flink 的实时推荐系统:从协同过滤到多模态语义理解

基于 Flink 的实时推荐系统&#xff1a;从协同过滤到多模态语义理解 嘿&#xff0c;各位技术小伙伴们&#xff01;在这个信息爆炸的时代&#xff0c;你是不是常常惊叹于各大平台仿佛能 “读懂你的心”&#xff0c;精准推送你感兴趣的内容呢&#xff1f;今天&#xff0c;小编就…...

Flink SQL、Hudi 、Doris在数据上的组合应用

Flink SQL、Hudi 和 Doris 是大数据领域中不同定位的技术组件&#xff0c;各自解决不同的问题&#xff0c;以下从核心定位、关键特性和典型场景三个维度展开说明&#xff1a; 1. Flink SQL&#xff1a;流批统一的实时计算引擎 核心定位&#xff1a;Flink 是 Apache 顶级的流批…...

Flink运维要点

一、Flink 运维核心策略 1. 集群部署与监控 资源规划 按业务优先级分配资源&#xff1a;核心作业优先保障内存和 CPU&#xff0c;避免资源竞争。示例&#xff1a;为实时风控作业分配专用 TaskManager&#xff0c;配置 taskmanager.memory.process.size8g。 监控体系 集成 Prom…...

VSCode + Cline AI辅助编程完全指南

VSCode Cline AI辅助编程完全指南 在当今AI快速发展的时代&#xff0c;程序员可以通过AI工具极大地提高工作效率。本教程将详细介绍如何使用VSCode结合Cline&#xff08;Claude AI助手&#xff09;进行AI辅助编程&#xff0c;帮助你提高开发效率&#xff0c;解决复杂问题。 …...

【源码级开发】Qwen3接入MCP,企业级智能体开发实战!

Qwen3接入MCP智能体开发实战&#xff08;上&#xff09; 一、MCP技术与Qwen3原生MCP能力介绍 1.智能体开发核心技术—MCP 1.1 Function calling技术回顾 如何快速开发一款智能体应用&#xff0c;最关键的技术难点就在于如何让大模型高效稳定的接入一些外部工具。而在MCP技术…...

回调函数应用示例

回调函数是一种通过函数指针&#xff08;或引用&#xff09;调用的函数&#xff0c;它在特定事件或条件发生时被另一个函数调用。回调函数的核心思想是将函数作为参数传递&#xff0c;以便在适当的时候执行自定义逻辑&#xff0c;常用于异步编程、事件驱动架构等场景。 业务场景…...

R语言如何解决导出pdf中文不显示的问题

前言 以前绘图都默认英文&#xff0c;突然要求都改成中文&#xff0c;呆住。。。。。。。。。 标题代码实现 ### 导入工具包 ### library(readr) library(dplyr) library(corrplot)df <- read_csv("./clinical.csv") df <- df %>% select(-id, -label)##…...

国产linux系统(银河麒麟,统信uos)使用 PageOffice自定义Word模版中的数据区域

​ PageOffice 国产版 &#xff1a;支持信创系统&#xff0c;支持银河麒麟V10和统信UOS&#xff0c;支持X86&#xff08;intel、兆芯、海光等&#xff09;、ARM&#xff08;飞腾、鲲鹏、麒麟等&#xff09;、龙芯&#xff08;Mips、LoogArch&#xff09;芯片架构。 在实际的Wor…...

llamafactory SFT 从断点恢复训练

背景 我使用llamafactory sft 微调模型的时候。gpu停止运行了。日志文件没有任何的报错信息。 显存还是占用状态。 查看llamafactory的进程是下述信息&#xff1a; 151312 151306 91 17:42 ? 03:58:10 [llamafactory-cl] 既然如此&#xff0c;那就只能从断点恢复训练了。 …...

C#里使用Prism.Core的例子

由于使用WPF来开发应用程序, 那么就会使用一些框架程序来加速开发,一般会使用Prism.Core来加速。 这个应用最后运行的显示如下: 第一步需要安装下面的包: <?xml version="1.0" encoding="utf-8"?> <packages><package id="Mi…...

【MySQL】数据库三大范式

目录 一. 什么是范式 二. 第一范式 三. 第二范式 不满足第二范式时可能出现的问题 四. 第三范式 一. 什么是范式 在数据库中范式其实就是一组规则&#xff0c;在我们设计数据库的时候&#xff0c;需要遵守不同的规则要求&#xff0c;设计出合理的关系型数据库&#xff0c;…...

window 显示驱动开发-分页视频内存资源

与 Microsoft Windows 2000 显示驱动程序模型不同&#xff0c;Windows Vista 显示驱动程序模型允许创建比可用物理视频内存总量更多的视频内存资源&#xff0c;然后根据需要分页进出视频内存。 换句话说&#xff0c;并非所有视频内存资源都同时位于视频内存中。 GPU 的管道中可…...

炼丹学习笔记3---ubuntu2004部署运行openpcdet记录

前言 环境 cuda 11.3 python 3.8 ubuntu2004 一、cuda环境检测 ylhy:~/code_ws/OpenPCDet/tools$ nvcc -V nvcc: NVIDIA (R) Cuda compiler driver Copyright (c) 2005-2021 NVIDIA Corporation Built on Sun_Mar_21_19:15:46_PDT_2021 Cuda compilation tools, release 11.3…...

美创科技针对《银行保险机构数据安全管理办法》解读

在数字化浪潮席卷下&#xff0c;银行保险业的运营模式发生了翻天覆地的变化&#xff0c;数据已然成为行业发展的核心驱动力。从客户基本信息、交易记录&#xff0c;到业务运营的关键数据、市场分析报告&#xff0c;海量数据背后潜藏巨大价值。然而&#xff0c;数据安全风险也随…...

activeMq 限制用户接收topic范围

1、在conf配置文件中找到jetty-realm.properties文件&#xff0c;添加用户信息 2、在broker标签中加入topic限制权限信息 <plugins><simpleAuthenticationPlugin><users><authenticationUser username"admin" password"admin" group…...

LIIGO ❤️ RUST 12 YEARS

LIIGO &#x1f496; RUST 12 YEARS 今天是RUST语言1.0发布十周年纪念日。十年前的今天&#xff0c;2015年的今天&#xff0c;Rust 1.0 正式发行。这是值得全球Rust支持者隆重纪念的日子。我借此机会衷心感谢Rust语言创始人Graydon Hoare&#xff0c;Mozilla公司&#xff0c;以…...

增量学习:机器学习领域中的资源高效利用秘籍

前言 在机器学习的广袤天地中&#xff0c;增量学习宛如一颗冉冉升起的新星&#xff0c;正逐渐展现出其独特的魅力和巨大的潜力。 它是一种能让 AI 模型像人类一样&#xff0c;逐步学习并不断强化自身知识&#xff0c;同时不会遗忘过往所学信息的学习方法。随着时代的飞速发展&a…...

OpenCV 背景建模详解:从原理到实战

在计算机视觉领域&#xff0c;背景建模是一项基础且重要的技术&#xff0c;它能够从视频流中分离出前景目标&#xff0c;广泛应用于运动目标检测、视频监控、人机交互等场景。OpenCV 作为计算机视觉领域最受欢迎的开源库之一&#xff0c;提供了多种高效的背景建模算法。本文将深…...

makefile细节说明

在 Makefile中&#xff0c;依赖关系的左右两部分有特定的名称&#xff1a; ​​左边部分&#xff08;冒号左侧&#xff09;​​ 称为 ​​目标&#xff08;Target&#xff09;​​ ​​右边部分&#xff08;冒号右侧&#xff09;​​ 称为 ​​依赖项&#xff08;Prerequisite…...

计算机图形学编程(使用OpenGL和C++)(第2版)学习笔记 10.增强表面细节(二)法线贴图

1. 法线贴图&#xff08;Normal Mapping&#xff09; 法线贴图是一种在3D图形渲染中广泛使用的表面细节增强技术。它通过存储每个像素的法线信息来模拟表面的细微凹凸细节&#xff0c;而无需增加实际的几何复杂度。 1.1. 工作原理 纹理存储 使用RGB通道存储法线向量的XYZ分量…...

使用 OpenCV 将图像中标记特定颜色区域

在计算机视觉任务中&#xff0c;颜色替换是一种常见的图像处理操作&#xff0c;广泛用于视觉增强、目标高亮、伪彩色渲染等场景。本文介绍一种简单而高效的方式&#xff0c;基于 OpenCV 检测图像中接近某种颜色的区域&#xff0c;并将其替换为反色&#xff08;对比色&#xff0…...

Service Mesh

目录 一、Service Mesh 的核心特点 二、Service Mesh 的典型架构 1. Sidecar 模式 2. 控制平面与数据平面分离 三、Service Mesh 解决的核心问题 四、典型应用场景 五、主流 Service Mesh 框架对比 六、挑战与局限性 七、未来趋势 总结 Istio 一、Istio 核心组件与…...

反射机制详细说明

反射机制详细说明 1. 反射的基本概念 反射(Reflection)是Java提供的一种在运行时(Runtime)动态获取类信息并操作类属性、方法和构造器的机制。通过反射,程序可以在运行时检查类、接口、字段和方法,并且可以实例化对象、调用方法、访问或修改字段值,甚至操作私有成员,…...

基于Mongodb的分布式文件存储实现

分布式文件存储的方案有很多&#xff0c;今天分享一个基于mongodb数据库来实现文件的存储&#xff0c;mongodb支持分布式部署&#xff0c;以此来实现文件的分布式存储。 基于 MongoDB GridFS 的分布式文件存储实现&#xff1a;从原理到实战 一、引言 当系统存在大量的图片、…...

相机Camera日志分析之九:高通相机Camx 基于预览1帧的ConfigureStreams二级日志分析详解

【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:高通相机Camx 日志分析之三:camx hal预览1帧logcat日志opencamera详解 相机Camera日志分析之三:不想输出每秒30帧巨量日志,如何只输出1帧日志作为学习使用? 这一篇我们开始讲: 高通相机Camx 日志…...

neo4j框架:ubuntu系统中neo4j安装与使用教程

在使用图数据库的时候&#xff0c;经常需要用到neo4j这一图数据库处理框架。本文详细介绍了neo4j安装使用过程中的问题与解决方法。 一、安装neo4j 在安装好了ubuntu系统、docker仓库和java的前提下 在ubuntu系统命令行依次输入如下命令&#xff1a; # 安装依赖库 sudo apt-…...

k8s灰度发布

基于 Traefik 的加权灰度发布-腾讯云开发者社区-腾讯云 Traefik | Traefik | v1.7 Releases traefik/traefik GitHub 从上面连接下载后上传到harbor虚拟机 vagrant upload /C/Users/HP280/Downloads/traefik 下载配置文件 wget -c http://raw.githubusercontent.com/conta…...

K8S从Harbor拉取镜像

参考 配置cri-docker使kubernetes1.24以docker作为运行时_启动cirdocker_跳跃音符#3712的博客-CSDN博客 部署Harbor私有容器镜像仓库并配置Kubernetes从Harbor拉取镜像的方法_运维个西瓜的博客-CSDN博客 K8S连接Harbor私有仓库_k8s harbor 登录-CSDN博客 K8S集群配置使用私…...