【计算机视觉1】----- 图像增强算法(对比度增强、直方图均衡化)

图像增强算法

图像增强算法收环境影响等问题需要综合考虑到光照、噪声、图像内容等因素,需采用合适的校正、自适应和多尺度处理方法,此外对算法本身的评估和优化也会影响最终处理的效果。
具体几种校正方式,可以参考【图像增强算法受环境影响几种校正方式】

·计算直方图

首先,统计图像中每个灰度级的像素数量,形成一个直方图。直方图表示了图像中不同灰度级的像素分布情况。

// 计算输入图像的最小灰度值和最大灰度值
    double minValue, maxValue;
    cv::minMaxLoc(image, &minValue, &maxValue);

    // 将图像的灰度值范围映射到更广泛的范围(例如,0-255)
    cv::Mat mappedImage;
    cv::convertScaleAbs(image, mappedImage, 255.0 / (maxValue - minValue), -minValue * 255.0 / (maxValue - minValue));

    // 显示原始图像和映射后的图像
    cv::imshow("原始图像", image);
    cv::imshow("映射后的图像", mappedImage);

    cv::waitKey(0);
    cv::destroyAllWindows();

minMaxLoc() 函数找到输入图像的最小灰度值和最大灰度值。然后,使用 convertScaleAbs() 函数将图像的灰度值范围映射到一个更广泛的范围(例如,0-255),以进行直方图修正。

最后,通过 imshow() 函数显示原始图像和灰度值范围映射后的图像。

请注意,这种方法只是简单地将图像的灰度值范围线性映射到一个更广泛的范围。对于更复杂的直方图修正方法,可能需要使用其他算法和技术。
假设输入图像为灰度图像。如果要计算彩色图像的直方图,需要先将图像转换为灰度图像。

·计算累积直方图

通过对直方图进行累积操作,计算出每个灰度级之前的像素总数。并将累积直方图归一化为表示图像中小于等于某个灰度级的像素所占比例。

// 计算直方图
    cv::Mat hist;
    int histSize = 256;
    float range[] = {
    
    0, 256};
    const float* histRange = {
    
    range};
    cv::calcHist(&image, 1, nullptr, cv::Mat(), hist, 1, &histSize, &histRange);

    // 计算累积直方图
    cv::Mat cumulativeHist(histSize, 1, CV_32F);
    cumulativeHist.at<float>(0) = hist.at<float>(0);
    for (int i = 1; i < histSize; ++i)
    {
    
    
        cumulativeHist.at<float>(i) = cumulativeHist.at<float>(i - 1) + hist.at<float>(i);
    }

    // 归一化累积直方图
    cv::normalize(cumulativeHist, cumulativeHist, 0, 1, cv::NORM_MINMAX);

calcHist() 函数计算输入图像的直方图,并通过累积操作计算出每个灰度级之前的像素总数。然后,使用 normalize() 函数将累积直方图归一化,以表示图像中小于等于某个灰度级的像素所占比例,imshow() 函数显示原始图像和累积直方图。

这边要注意,假设输入图像为灰度图像,如果要计算彩色图像的直方图或累积直方图,需要将图像转换为灰度图像或分别对各个通道进行处理。

·归一化累积直方图

归一化累积直方图的原理是将累积直方图的取值范围映射到 [0, 1] 之间,使其具有统一的尺度。这样做的目的是消除不同图像之间的像素总数差异,使得它们的累积直方图能够更好地进行比较和分析。

// 计算累积直方图
std::vector<int> computeCumulativeHistogram(const std::vector<int>& histogram) 
{
    
    
    std::vector<int> cumulativeHistogram(histogram.size(), 0);
    cumulativeHistogram[0] = histogram[0];

    for (int i = 1; i < histogram.size(); ++i) {
    
    
        cumulativeHistogram[i] = cumulativeHistogram[i - 1] + histogram[i];
    }

    return cumulativeHistogram;
}

// 归一化累积直方图
std::vector<double> normalizeCumulativeHistogram(const std::vector<int>& cumulativeHistogram, int totalPixels)
{
    
    
    std::vector<double> normalizedHistogram(cumulativeHistogram.size());

    for (int i = 0; i < cumulativeHistogram.size(); ++i) {
    
    
        normalizedHistogram[i] = static_cast<double>(cumulativeHistogram[i]) / totalPixels;
    }

    return normalizedHistogram;
}
void CalculatehistogramModel
{
    
    
  // 示例直方图
    std::vector<int> histogram = {
    
    10, 20, 30, 40, 50};

    // 计算累积直方图
    std::vector<int> cumulativeHistogram = computeCumulativeHistogram(histogram);

    // 总像素数
    int totalPixels = cumulativeHistogram.back();

    // 归一化累积直方图
    std::vector<double> normalizedHistogram = normalizeCumulativeHistogram(cumulativeHistogram, totalPixels);
}

1.定义computeCumulativeHistogramnormalizeCumulativeHistogram函数,用于计算累积直方图和归一化累积直方图,computeCumulativeHistogram 函数接收一个直方图作为输入,返回计算得到的累积直方图。我们使用一个循环遍历直方图的每个灰度级,并将当前灰度级的像素值与前一个灰度级的累积值相加,以获得当前灰度级的累积直方图值。

2.normalizeCumulativeHistogram 函数接收累积直方图和总像素数作为输入,返回归一化的累积直方图。在此函数中,我们使用一个循环遍历累积直方图的每个值,并将其除以总像素数,以获得每个灰度级在图像中的占比,在 CalculatehistogramModel函数中,定义了一个直方图 histogram,其中包含了一些灰度级的像素数量,调用 computeCumulativeHistogram 函数,将示例直方图作为参数传递给它,以获得累积直方图。

3…获取累积直方图中的最后一个值,即总像素数,调用 normalizeCumulativeHistogram 函数,将累积直方图和总像素数作为参数传递给normalizeCumulativeHistogram函数,以获得归一化的累积直方图。
这样,得到了归一化的累积直方图,其中每个灰度级在图像中的占比值都被限制在 [0, 1] 范围内。

·计算目标直方图

计算目标直方图通常是指计算一幅图像或者一段图像区域中某个特定目标的灰度级分布情况。

// 计算目标直方图
std::vector<int> computeTargetHistogram(const std::vector<std::vector<int>>& image, int targetValue) {
    
    
    std::vector<int> histogram(256, 0);

    for (const auto& row : image) {
    
    
        for (int pixelValue : row) {
    
    
            if (pixelValue == targetValue) {
    
    
                histogram[pixelValue]++;
            }
        }
    }

    return histogram;
    
// 归一化直方图
std::vector<double> normalizeHistogram(const std::vector<int>& histogram, int totalPixels) {
    
    
    std::vector<double> normalizedHistogram(histogram.size());

    for (int i = 0; i < histogram.size(); ++i) {
    
    
        normalizedHistogram[i] = static_cast<double>(histogram[i]) / totalPixels;
    }

    return normalizedHistogram;
}

     // 示例图像
    std::vector<std::vector<int>> image = {
    
    
        {
    
    0, 1, 2, 2, 1},
        {
    
    1, 3, 2, 0, 2},
        {
    
    2, 1, 2, 3, 0},
        {
    
    2, 2, 1, 0, 1}
       };
    // 目标灰度级
    int targetValue = 2;

    // 计算目标直方图
    std::vector<int> targetHistogram = computeTargetHistogram(image, targetValue);
}

1.定义computeTargetHistogramnormalizeHistogram函数。用于计算目标直方图和归一化直方图。

2.computeTargetHistogram 函数接收一个图像和目标灰度级作为输入,返回计算得到的目标直方图。使用两个嵌套循环遍历图像中的每个像素值,并统计目标灰度级出现的次数,将其记录在对应的直方图位置上。

3.normalizeHistogram 函数接收直方图和总像素数作为输入,返回归一化的直方图。在此函数中,使用一个循环遍历直方图的每个值,并将其除以总像素数,以获得每个灰度级在图像中的占比。在 main 函数中,我们定义了一个示例图像 image,其中包含了一些像素值。

4.指定了目标灰度级 targetValue,用于计算目标直方图,调用 computeTargetHistogram 函数,将示例图像和目标灰度级作为参数传递给它,以获得目标直方图。计算总像素数,遍历图像的每一行,累加每一行的像素数量。

5.调用 normalizeHistogram 函数,将目标直方图和总像素数作为参数传递给它,以获得归一化的直方图。使用一个循环遍历归一化直方图的每个值。

这样,就得到了目标直方图和归一化的目标直方图,用于表示图像或图像区域中特定目标的灰度级分布情况。

·直方图映射(Histogram Equalization)

直方图映射是一种常用的图像增强技术,通过对图像的直方图进行调整,使得图像的对比度增强。


// 直方图映射
std::vector<int> histogramMapping(const std::vector<std::vector<int>>& image, const std::vector<int>& histogram) {
    
    
    std::vector<int> mappedImage;

    // 计算映射函数
    std::vector<int> mappingFunction(256, 0);
    int totalPixels = 0;
    for (int i = 0; i < histogram.size(); ++i) {
    
    
        totalPixels += histogram[i];
        mappingFunction[i] = static_cast<int>(round(255.0 * totalPixels / (image.size() * image[0].size())));
    }

    // 进行直方图映射
    for (const auto& row : image) {
    
    
        for (int pixelValue : row) {
    
    
            mappedImage.push_back(mappingFunction[pixelValue]);
        }
    }

    return mappedImage;
int main() {
    
    
    // 示例图像
    std::vector<std::vector<int>> image = {
    
    
        {
    
    100, 150, 200},
        {
    
    50, 75, 100},
        {
    
    200, 175, 125}
    };

    // 计算原始图像的直方图
    std::vector<int> histogram = computeHistogram(image);

    // 进行直方图映射
    std::vector<int> mappedImage = histogramMapping(image, histogram);
}

定义histogramMapping函数,用于计算原始图像的直方图和进行直方图映射,函数接收图像和原始图像的直方图作为输入,返回经过直方图映射后的图像。在此函数中,我们首先计算映射函数,即将原始图像的灰度级映射到新的灰度级。我们使用一个循环遍历原始图像直方图的每个灰度级,计算每个灰度级在新图像中所占的像素数量。定义一个嵌套循环遍历原始图像的函数循环遍历原始图像中的每个像素值,并根据映射函数将其映射到新的灰度级,将映射后的像素值存储在新的图像中。

将示例图像和原始图像的直方图作为参数传递给histogramMapping函数,以获得经过直方图映射后的图像。通过直方图映射后的图像,我们可以增强图像的对比度,是的图像像素中的细节更加明显。

·直方图均衡化

将图像的直方图进行变换,将原始图像的灰度级分布映射到一个更广泛的范围,从而增强图像的视觉效果。

// 计算直方图
    cv::Mat hist;
    int histSize = 256;
    float range[] = {
    
    0, 256};
    const float* histRange = {
    
    range};
    cv::calcHist(&image, 1, nullptr, cv::Mat(), hist, 1, &histSize, &histRange);

    // 计算累积直方图
    cv::Mat cumulativeHist(histSize, 1, CV_32F);
    cumulativeHist.at<float>(0) = hist.at<float>(0);
    for (int i = 1; i < histSize; ++i)
    {
    
    
        cumulativeHist.at<float>(i) = cumulativeHist.at<float>(i - 1) + hist.at<float>(i);
    }

    // 归一化累积直方图
    cv::normalize(cumulativeHist, cumulativeHist, 0, histSize - 1, cv::NORM_MINMAX);

    // 映射灰度值
    cv::Mat equalizedImage = image.clone();
    for (int i = 0; i < image.rows; ++i)
    {
    
    
        for (int j = 0; j < image.cols; ++j)
        {
    
    
            int pixel = image.at<uchar>(i, j);
            equalizedImage.at<uchar>(i, j) = cv::saturate_cast<uchar>(cumulativeHist.at<float>(pixel));
        }
    }

    // 显示原始图像、直方图和均衡化后的图像
    cv::imshow("原始图像", image);
    cv::imshow("直方图", hist);
    cv::imshow("均衡化后的图像", equalizedImage);

    cv::waitKey(0);
    cv::destroyAllWindows();

这段代码示例实现了一个基本的直方图修正算法,但要注意,这是一个全局的图像增强方法,可能会增加图像中噪声的可见性。在实际应用中,可能需要结合其他技术来进一步改进图像的质量和视觉效果。

猜你喜欢

转载自blog.csdn.net/weixin_43504942/article/details/130790245