前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >《Automatic Color Equalization and its Fast Implementation》图像论文复现

《Automatic Color Equalization and its Fast Implementation》图像论文复现

作者头像
BBuf
发布2019-12-04 18:11:43
6980
发布2019-12-04 18:11:43
举报
文章被收录于专栏:GiantPandaCV

前言

这篇论文实际上也是《快速ACE算法及其在图像拼接中的应用》这篇论文中的快速ACE算法,我用C++实现了,现在放出来。

算法原理

在论文介绍中,提到高动态图像是指在一幅图像中,既有明亮的区域又有阴影区域,为了使细节清晰,需要满足以下几点: (1)对动态范围具有一定的压缩能力 (2)对亮暗区域的细节有一定的显示能力 (3)满足(1),(2)的条件下不破坏图像的清晰度 Rizzi等根据Retinex理论提出自动颜色均衡算法,该算法考虑了图像中颜色和亮度的空间位置关系,进行局部的自适应滤波,实现具有局部和非线性特点的图像亮度,色度,对比度调整,同时满足灰度世界理论和白斑点假设。

算法步骤

论文中还有一个优化部分,感兴趣可以去看看,并且作者也是有开源代码的。下面给一个C++代码实现,有2种实现,一种是常规实现,另外一种是递归实现,速度稍快。

代码实现

代码语言:javascript
复制
#include <stdio.h>
#include <iostream>
#include <immintrin.h>
#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/ml/ml.hpp>
#include "opencv2/highgui/highgui.hpp"
using namespace cv;
using namespace cv::ml;
using namespace std;

namespace ACE {
  //Gray
  Mat stretchImage(Mat src) {
    int row = src.rows;
    int col = src.cols;
    Mat dst(row, col, CV_64FC1);
    double MaxValue = 0;
    double MinValue = 256.0;
    for (int i = 0; i < row; i++) {
      for (int j = 0; j < col; j++) {
        MaxValue = max(MaxValue, src.at<double>(i, j));
        MinValue = min(MinValue, src.at<double>(i, j));
      }
    }
    for (int i = 0; i < row; i++) {
      for (int j = 0; j < col; j++) {
        dst.at<double>(i, j) = (1.0 * src.at<double>(i, j) - MinValue) / (MaxValue - MinValue);
        if (dst.at<double>(i, j) > 1.0) {
          dst.at<double>(i, j) = 1.0;
        }
        else if (dst.at<double>(i, j) < 0) {
          dst.at<double>(i, j) = 0;
        }
      }
    }
    return dst;
  }

  Mat getPara(int radius) {
    int size = radius * 2 + 1;
    Mat dst(size, size, CV_64FC1);
    for (int i = -radius; i <= radius; i++) {
      for (int j = -radius; j <= radius; j++) {
        if (i == 0 && j == 0) {
          dst.at<double>(i + radius, j + radius) = 0;
        }
        else {
          dst.at<double>(i + radius, j + radius) = 1.0 / sqrt(i * i + j * j);
        }
      }
    }
    double sum = 0;
    for (int i = 0; i < size; i++) {
      for (int j = 0; j < size; j++) {
        sum += dst.at<double>(i, j);
      }
    }
    for (int i = 0; i < size; i++) {
      for (int j = 0; j < size; j++) {
        dst.at<double>(i, j) = dst.at<double>(i, j) / sum;
      }
    }
    return dst;
  }

  Mat NormalACE(Mat src, int ratio, int radius) {
    Mat para = getPara(radius);
    int row = src.rows;
    int col = src.cols;
    int size = 2 * radius + 1;
    Mat Z(row + 2 * radius, col + 2 * radius, CV_64FC1);
    for (int i = 0; i < Z.rows; i++) {
      for (int j = 0; j < Z.cols; j++) {
        if((i - radius >= 0) && (i - radius < row) && (j - radius >= 0) && (j - radius < col)) {
          Z.at<double>(i, j) = src.at<double>(i - radius, j - radius);
        }
        else {
          Z.at<double>(i, j) = 0;
        }
      }
    }

    Mat dst(row, col, CV_64FC1);
    for (int i = 0; i < row; i++) {
      for (int j = 0; j < col; j++) {
        dst.at<double>(i, j) = 0.f;
      }
    }
    for (int i = 0; i < size; i++) {
      for (int j = 0; j < size; j++) {
        if (para.at<double>(i, j) == 0) continue;
        for (int x = 0; x < row; x++) {
          for (int y = 0; y < col; y++) {
            double sub = src.at<double>(x, y) - Z.at<double>(x + i, y + j);
            double tmp = sub * ratio;
            if (tmp > 1.0) tmp = 1.0;
            if (tmp < -1.0) tmp = -1.0;
            dst.at<double>(x, y) += tmp * para.at<double>(i, j);
          }
        }
      }
    }
    return dst;
  }

  Mat FastACE(Mat src, int ratio, int radius) {
    int row = src.rows;
    int col = src.cols;
    if (min(row, col) <= 2) {
      Mat dst(row, col, CV_64FC1);
      for (int i = 0; i < row; i++) {
        for (int j = 0; j < col; j++) {
          dst.at<double>(i, j) = 0.5;
        }
      }
      return dst;
    }
    
    Mat Rs((row + 1) / 2, (col + 1) / 2, CV_64FC1);
    
    resize(src, Rs, Size((col + 1) / 2, (row + 1) / 2));
    Mat Rf= FastACE(Rs, ratio, radius);
    resize(Rf, Rf, Size(col, row));
    resize(Rs, Rs, Size(col, row));
    Mat dst(row, col, CV_64FC1);
    Mat dst1 = NormalACE(src, ratio, radius);
    Mat dst2 = NormalACE(Rs, ratio, radius);
    for (int i = 0; i < row; i++) {
      for (int j = 0; j < col; j++) {
        dst.at<double>(i, j) = Rf.at<double>(i, j) + dst1.at<double>(i, j) - dst2.at<double>(i, j);
      }
    }
    return dst;
  }

  Mat getACE(Mat src, int ratio, int radius) {
    int row = src.rows;
    int col = src.cols;
    vector <Mat> v;
    split(src, v);
    v[0].convertTo(v[0], CV_64FC1);
    v[1].convertTo(v[1], CV_64FC1);
    v[2].convertTo(v[2], CV_64FC1);
    Mat src1(row, col, CV_64FC1);
    Mat src2(row, col, CV_64FC1);
    Mat src3(row, col, CV_64FC1);

    for (int i = 0; i < row; i++) {
      for (int j = 0; j < col; j++) {
        src1.at<double>(i, j) = 1.0 * src.at<Vec3b>(i, j)[0] / 255.0;
        src2.at<double>(i, j) = 1.0 * src.at<Vec3b>(i, j)[1] / 255.0;
        src3.at<double>(i, j) = 1.0 * src.at<Vec3b>(i, j)[2] / 255.0;
      }
    }
    src1 = stretchImage(FastACE(src1, ratio, radius));
    src2 = stretchImage(FastACE(src2, ratio, radius));
    src3 = stretchImage(FastACE(src3, ratio, radius));

    Mat dst1(row, col, CV_8UC1);
    Mat dst2(row, col, CV_8UC1);
    Mat dst3(row, col, CV_8UC1);
    for (int i = 0; i < row; i++) {
      for (int j = 0; j < col; j++) {
        dst1.at<uchar>(i, j) = (int)(src1.at<double>(i, j) * 255);
        if (dst1.at<uchar>(i, j) > 255) dst1.at<uchar>(i, j) = 255;
        else if (dst1.at<uchar>(i, j) < 0) dst1.at<uchar>(i, j) = 0;
        dst2.at<uchar>(i, j) = (int)(src2.at<double>(i, j) * 255);
        if (dst2.at<uchar>(i, j) > 255) dst2.at<uchar>(i, j) = 255;
        else if (dst2.at<uchar>(i, j) < 0) dst2.at<uchar>(i, j) = 0;
        dst3.at<uchar>(i, j) = (int)(src3.at<double>(i, j) * 255);
        if (dst3.at<uchar>(i, j) > 255) dst3.at<uchar>(i, j) = 255;
        else if (dst3.at<uchar>(i, j) < 0) dst3.at<uchar>(i, j) = 0;
      }
    }
    vector <Mat> out;
    out.push_back(dst1);
    out.push_back(dst2);
    out.push_back(dst3);
    Mat dst;
    merge(out, dst);
    return dst;
  }
}

using namespace ACE;

int main() {
  Mat src = imread("F:\\sky.jpg");
  Mat dst = getACE(src, 4, 7);
  imshow("origin", src);
  imshow("result", dst);
  waitKey(0);
}

效果展示

后记

实现的效果和论文有所偏差,这只是拿来参考一下,对这个感兴趣可以研究作者给出的C++源码哦。

补充问题

关于Automatic Color Equalization和Automatic Color Enhancement的区别。

参考文章

https://blog.csdn.net/piaoxuezhong/article/details/78357815 https://www.cnblogs.com/whw19818/p/5765995.html

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-10-31,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 GiantPandaCV 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 算法原理
  • 算法步骤
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档