跳转至

算法原理

这个论文是中文的,论文网址在这:http://html.rhhz.net/JSJYY/2017-2-564.htm 。算法原理可以直接在这个网址或者下载论文查看。 关于RGB和HSI的相互转换,大家可以尝试这个博客列出的一些算法,本人程序在转换部分没有写好,自己尝试实现即可,但整体逻辑在matlab对拍测试无误,用这个博客第一种算法会出现色斑,由于这个论文的意义不是很大,就没有尝试后面的转换算法了。有兴趣可以结合我的代码去尝试一下。

源码实现

#include "iostream"
#include "opencv2/opencv.hpp"
#include <opencv2/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <math.h>
using namespace std;
using namespace cv;

double log2(double N) {
    return log10(N) / log10(2.0);
}

Mat Inrbl(Mat src, double k) {
    int row = src.rows;
    int col = src.cols;
    Mat dst(row, col, CV_8UC3);
    Mat dsthsi(row, col, CV_64FC3);

    //RGB2HSI
    Mat HH = Mat(row, col, CV_64FC1);
    Mat SS = Mat(row, col, CV_64FC1);
    Mat II = Mat(row, col, CV_64FC1);
    int mp[256] = { 0 };
    double mp2[256] = { 0.0 };
    for (int i = 0; i < row; i++) {
        for (int j = 0; j < col; j++) {
            double b = src.at<Vec3b>(i, j)[0] / 255.0;
            double g = src.at<Vec3b>(i, j)[1] / 255.0;
            double r = src.at<Vec3b>(i, j)[2] / 255.0;
            double minn = min(b, min(g, r));
            double maxx = max(b, max(g, r));
            double H = 0;
            double S = 0;
            double I = (minn + maxx) / 2.0f;
            if (maxx == minn) {
                dsthsi.at<Vec3f>(i, j)[0] = H;
                dsthsi.at<Vec3f>(i, j)[1] = S;
                dsthsi.at<Vec3f>(i, j)[2] = I;
                HH.at<double>(i, j) = H;
                SS.at<double>(i, j) = S;
                II.at<double>(i, j) = I;
            }
            else {
                double delta = maxx - minn;
                if (I < 0.5) {
                    S = delta / (maxx + minn);
                }
                else {
                    S = delta / (2.0 - maxx - minn);
                }
                if (r == maxx) {
                    if (g > b) {
                        H = (g - b) / delta;
                    }
                    else {
                        H = 6.0 + (g - b) / delta;
                    }
                }
                else if (g == maxx) {
                    H = 2.0 + (b - r) / delta;
                }
                else {
                    H = 4.0 + (r - g) / delta;
                }
                H /= 6.0; //除以6,表示在那个部分
                if (H < 0.0)
                    H += 1.0;
                if (H > 1)
                    H -= 1;
                H = (int)(H * 360); //转成[0, 360]
                dsthsi.at<Vec3f>(i, j)[0] = H;
                dsthsi.at<Vec3f>(i, j)[1] = S;
                dsthsi.at<Vec3f>(i, j)[2] = I;
                HH.at<double>(i, j) = H;
                SS.at<double>(i, j) = S;
                II.at<double>(i, j) = I;
            }
        }
    }
    for (int i = 0; i < row; i++) {
        for (int j = 0; j < col; j++) {
            mp[(int)((src.at<Vec3b>(i, j)[0] + src.at<Vec3b>(i, j)[1] + src.at<Vec3b>(i, j)[2]) / 3)]++;
        }
    }
    //Ostu阈值
    for (int i = 0; i < 256; i++) {
        mp2[i] = (double)mp[i] / (double)(row * col);
    }
    double mI = 0;
    for (int i = 0; i < 256; i++) {
        mI += (i / 255.0)  * mp2[i];
    }
    double var = 0;
    double ThresHold = 0;
    for (int i = 0; i < 256; i++) {
        double T = 1.0 * i / 256;
        double P1 = 0.0;
        double mT = 0.0;
        for (int j = 0; j <= i; j++) {
            P1 += mp2[j];
            mT += (double)(j / 255.0) * mp2[j];
        }
        if (P1 == 0) continue;
        if (((mI*P1 - mT)*(mI*P1 - mT) / (P1*(1 - P1))) > var) {
            var = (mI*P1 - mT)*(mI*P1 - mT) / (P1*(1 - P1));
            ThresHold = T;
        }
    }

    //
    int cnt = 0;
    for (int i = 0; i < row; i++) {
        for (int j = 0; j < col; j++) {
            if (II.at<double>(i, j) <= ThresHold) {
                cnt++;
            }
        }
    }
    printf("cnt: %d\n", cnt);
    double A = k * sqrt((double)cnt / (double)(row * col - cnt));
    printf("A: %.5f\n", A);
    for (int i = 0; i < row; i++) {
        for (int j = 0; j < col; j++) {
            double D, C;
            if (II.at<double>(i, j) <= ThresHold) {
                D = A;
                C = 1.0 / log2(D + 1.0);
            }
            else {
                D = (double)(ThresHold * A - ThresHold) / double((1 - ThresHold) * (II.at<double>(i, j))) - (double)(ThresHold * A - 1.0) / (1.0 - ThresHold);
                C = 1.0 / log2(D + 1);
            }
            II.at<double>(i, j) = (C * log2(D * (double)II.at<double>(i, j) + 1.0));
        }
    }//

     //HSI2RGB
    for (int i = 0; i < row; i++) {
        for (int j = 0; j < col; j++) {
            double r, g, b, M1, M2;
            double H = HH.at<double>(i, j);
            double S = SS.at<double>(i, j);
            double I = II.at<double>(i, j);
            double hue = H / 360;
            if (S == 0) {//灰色
                r = g = b = I;
            }
            else {
                if (I <= 0.5) {
                    M2 = I * (1.0 + S);
                }
                else {
                    M2 = I + S - I * S;
                }
                M1 = (2.0 * I - M2);
                r = get_Ans(M1, M2, hue + 1.0 / 3.0);
                g = get_Ans(M1, M2, hue);
                b = get_Ans(M1, M2, hue - 1.0 / 3.0);
            }
            dst.at<Vec3b>(i, j)[0] = (int)(b * 255);
            dst.at<Vec3b>(i, j)[1] = (int)(g * 255);
            dst.at<Vec3b>(i, j)[2] = (int)(r * 255);
        }
    }
    return dst;
}

int main() {
    Mat src = cv::imread("G:\\1.jpg");
    Mat dst = Inrbl(src, 50);
    cv::imshow("origin", src);
    cv::imshow("result", dst);
    waitKey(0);
    return 0;
}

算法效果

这里提供一张原图供测试。

在这里插入图片描述

效果图:

在这里插入图片描述