图像增强

Mat ImageAHE(Mat img, int block)
{
    Mat AHE_GO = img.clone();

    int width = img.cols;
    int height = img.rows;
    int width_block = width / block; //每个小格子的长和宽
    int height_block = height / block;
    //存储各个直方图


    int tmp2[16 * 16][256] = { 0 };//10要和block保持一致
    float C2[16 * 16][256] = { 0.0 };
    //分块
    int total = width_block * height_block;//分割的总的块儿数
    for (int i = 0; i < block; i++)
    {
        for (int j = 0; j < block; j++)
        {
            int start_x = i * width_block;
            int end_x = start_x + width_block;
            int start_y = j * height_block;
            int end_y = start_y + height_block;

            int num = i + block * j;
            //遍历小块,计算直方图
            for (int ii = start_x; ii < end_x; ii++)
            {
                for (int jj = start_y; jj < end_y; jj++)
                {
                    int index = img.at<uchar>(jj, ii);
                    tmp2[num][index]++;
                }
            }
            //计算累积分布直方图
            for (int k = 0; k < 256; k++)
            {
                if (k == 0)
                    C2[num][k] = 1.0f * tmp2[num][k] / total;
                else
                    C2[num][k] = C2[num][k - 1] + 1.0f * tmp2[num][k] / total;
            }
        }
    }
    //将统计结果写入
    for (int i = 0; i < block; i++)
    {
        for (int j = 0; j < block; j++)
        {
            int start_x = i * width_block;
            int end_x = start_x + width_block;
            int start_y = j * height_block;
            int end_y = start_y + height_block;
            int num = i + block * j;
            //遍历小块,计算直方图
            for (int ii = start_x; ii < end_x; ii++)
            {
                for (int jj = start_y; jj < end_y; jj++)
                {
                    int index = img.at<uchar>(jj, ii);
                    //结果直接写入AHE_GO中去
                    AHE_GO.at<uchar>(jj, ii) = C2[num][index] * 255;
                }
            }
        }
    }
    return AHE_GO;
}

Mat ImageEqaualize(Mat img)
{
    int width = img.cols;
    int height = img.rows;
    Mat HT_GO = img.clone();
    int tmp[256] = { 0 };
    float C[256] = { 0.0 };
    int total = width * height;
    for (int i = 0; i < img.rows; i++)
    {
        for (int j = 0; j < img.cols; j++)
        {
            int index = img.at<uchar>(i, j);
            tmp[index] ++;
        }
    }
    //计算累积函数
    for (int i = 0; i < 256; i++) {
        if (i == 0)
            C[i] = 1.0f * tmp[i] / total;
        else
            C[i] = C[i - 1] + 1.0f * tmp[i] / total;
    }
    //这里的累积函数分配的方法非常直观高效
    for (int i = 0; i < img.rows; i++) {
        for (int j = 0; j < img.cols; j++) {
            int index = img.at<uchar>(i, j);
            HT_GO.at<uchar>(i, j) = C[index] * 255;
        }
    }
    return HT_GO;
}

Mat ImageClHe(Mat img, int block)
{
    int width = img.cols/ block;
    int height = img.rows/ block;
    Mat CLHE_GO = img.clone();
    int tmp[256] = { 0 };
    float C[256] = { 0.0 };
    int total = width * height;
    for (int i = 0; i < img.rows; i++)
    {
        for (int j = 0; j < img.cols; j++)
        {
            int index = img.at<uchar>(i, j);
            tmp[index] ++;
        }
    }
    /////////////////////////限制对比度计算部分,注意这个地方average的计算不一定科学
    int average = width * height / 255 /64;
    int LIMIT = 4 * average;
    int steal = 0;
    for (int k = 0; k < 256; k++)
    {
        if (tmp[k] > LIMIT) {
            steal += tmp[k] - LIMIT;
            tmp[k] = LIMIT;
        }
    }
    int bonus = steal / 256;
    //hand out the steals averagely
    for (int k = 0; k < 256; k++)
    {
        tmp[k] += bonus;
    }
    ///////////////////////////////////////////
    //计算累积函数
    for (int i = 0; i < 256; i++) {
        if (i == 0)
            C[i] = 1.0f * tmp[i] / total;
        else
            C[i] = C[i - 1] + 1.0f * tmp[i] / total;
    }
    //这里的累积函数分配的方法非常直观高效
    for (int i = 0; i < img.rows; i++) {
        for (int j = 0; j < img.cols; j++) {
            int index = img.at<uchar>(i, j);
            CLHE_GO.at<uchar>(i, j) = C[index] * 255;
        }
    }
    return CLHE_GO;
}

Mat ImageClHeNoInter(Mat img, int block)
{
    Mat CLAHE_GO = img.clone();

    int width = img.cols;
    int height = img.rows;
    int width_block = width / block; //每个小格子的长和宽
    int height_block = height / block;
    //存储各个直方图
    int tmp2[8 * 8][256] = { 0 };
    float C2[8 * 8][256] = { 0.0 };
    //分块
    int total = width_block * height_block;
    for (int i = 0; i < block; i++)
    {
        for (int j = 0; j < block; j++)
        {
            int start_x = i * width_block;
            int end_x = start_x + width_block;
            int start_y = j * height_block;
            int end_y = start_y + height_block;
            int num = i + block * j;
            //遍历小块,计算直方图
            for (int ii = start_x; ii < end_x; ii++)
            {
                for (int jj = start_y; jj < end_y; jj++)
                {
                    int index = img.at<uchar>(jj, ii);
                    tmp2[num][index]++;
                }
            }
            //裁剪和增加操作,也就是clahe中的cl部分
            //这里的参数 对应《Gem》上面 fCliplimit  = 4  , uiNrBins  = 255
            int average = width_block * height_block / 255;
            int LIMIT = 4 * average;
            int steal = 0;
            for (int k = 0; k < 256; k++)
            {
                if (tmp2[num][k] > LIMIT) {
                    steal += tmp2[num][k] - LIMIT;
                    tmp2[num][k] = LIMIT;
                }
            }
            int bonus = steal / 256;
            //hand out the steals averagely
            for (int k = 0; k < 256; k++)
            {
                tmp2[num][k] += bonus;
            }
            //计算累积分布直方图
            for (int k = 0; k < 256; k++)
            {
                if (k == 0)
                    C2[num][k] = 1.0f * tmp2[num][k] / total;
                else
                    C2[num][k] = C2[num][k - 1] + 1.0f * tmp2[num][k] / total;
            }
        }
    }
    //计算变换后的像素值
    //将统计结果写入
    for (int i = 0; i < block; i++)
    {
        for (int j = 0; j < block; j++)
        {
            int start_x = i * width_block;
            int end_x = start_x + width_block;
            int start_y = j * height_block;
            int end_y = start_y + height_block;
            int num = i + block * j;
            //遍历小块,计算直方图
            for (int ii = start_x; ii < end_x; ii++)
            {
                for (int jj = start_y; jj < end_y; jj++)
                {
                    int index = img.at<uchar>(jj, ii);
                    //结果直接写入AHE_GO中去
                    CLAHE_GO.at<uchar>(jj, ii) = C2[num][index] * 255;
                }
            }
        }

    }
    return CLAHE_GO;
}

Mat ImageClahe(Mat img, int block)
{
    Mat CLAHE_GO = img.clone();
    //int block = _step;//pblock
    int width = img.cols;
    int height = img.rows;
    int width_block = width / block; //每个小格子的长和宽
    int height_block = height / block;
    //存储各个直方图
    int tmp2[8 * 8][256] = { 0 };
    float C2[8 * 8][256] = { 0.0 };
    //分块
    int total = width_block * height_block;
    for (int i = 0; i < block; i++)
    {
        for (int j = 0; j < block; j++)
        {
            int start_x = i * width_block;
            int end_x = start_x + width_block;
            int start_y = j * height_block;
            int end_y = start_y + height_block;
            int num = i + block * j;
            //遍历小块,计算直方图
            for (int ii = start_x; ii < end_x; ii++)
            {
                for (int jj = start_y; jj < end_y; jj++)
                {
                    int index = img.at<uchar>(jj, ii);
                    tmp2[num][index]++;
                }
            }
            //裁剪和增加操作,也就是clahe中的cl部分
            //这里的参数 对应《Gem》上面 fCliplimit = 4 , uiNrBins = 255
            int average = width_block * height_block / 255;
            //关于参数如何选择,需要进行讨论。不同的结果进行讨论
            //关于全局的时候,这里的这个cl如何算,需要进行讨论
            int LIMIT = 40 * average;
            int steal = 0;
            for (int k = 0; k < 256; k++)
            {
                if (tmp2[num][k] > LIMIT) {
                    steal += tmp2[num][k] - LIMIT;
                    tmp2[num][k] = LIMIT;
                }
            }
            int bonus = steal / 256;
            //hand out the steals averagely
            for (int k = 0; k < 256; k++)
            {
                tmp2[num][k] += bonus;
            }
            //计算累积分布直方图
            for (int k = 0; k < 256; k++)
            {
                if (k == 0)
                    C2[num][k] = 1.0f * tmp2[num][k] / total;
                else
                    C2[num][k] = C2[num][k - 1] + 1.0f * tmp2[num][k] / total;
            }
        }
    }
    //计算变换后的像素值
    //根据像素点的位置,选择不同的计算方法
    for (int i = 0; i < width; i++)
    {
        for (int j = 0; j < height; j++)
        {
            //four coners
            if (i <= width_block / 2 && j <= height_block / 2)
            {
                int num = 0;
                CLAHE_GO.at<uchar>(j, i) = (int)(C2[num][CLAHE_GO.at<uchar>(j, i)] * 255);
            }
            else if (i <= width_block / 2 && j >= ((block - 1)*height_block + height_block / 2)) {
                int num = block * (block - 1);
                CLAHE_GO.at<uchar>(j, i) = (int)(C2[num][CLAHE_GO.at<uchar>(j, i)] * 255);
            }
            else if (i >= ((block - 1)*width_block + width_block / 2) && j <= height_block / 2) {
                int num = block - 1;
                CLAHE_GO.at<uchar>(j, i) = (int)(C2[num][CLAHE_GO.at<uchar>(j, i)] * 255);
            }
            else if (i >= ((block - 1)*width_block + width_block / 2) && j >= ((block - 1)*height_block + height_block / 2)) {
                int num = block * block - 1;
                CLAHE_GO.at<uchar>(j, i) = (int)(C2[num][CLAHE_GO.at<uchar>(j, i)] * 255);
            }
            //four edges except coners
            else if (i <= width_block / 2)
            {
                //线性插值
                int num_i = 0;
                int num_j = (j - height_block / 2) / height_block;
                int num1 = num_j * block + num_i;
                int num2 = num1 + block;
                float p = (j - (num_j*height_block + height_block / 2)) / (1.0f*height_block);
                float q = 1 - p;
                CLAHE_GO.at<uchar>(j, i) = (int)((q*C2[num1][CLAHE_GO.at<uchar>(j, i)] + p * C2[num2][CLAHE_GO.at<uchar>(j, i)]) * 255);
            }
            else if (i >= ((block - 1)*width_block + width_block / 2)) {
                //线性插值
                int num_i = block - 1;
                int num_j = (j - height_block / 2) / height_block;
                int num1 = num_j * block + num_i;
                int num2 = num1 + block;
                float p = (j - (num_j*height_block + height_block / 2)) / (1.0f*height_block);
                float q = 1 - p;
                CLAHE_GO.at<uchar>(j, i) = (int)((q*C2[num1][CLAHE_GO.at<uchar>(j, i)] + p * C2[num2][CLAHE_GO.at<uchar>(j, i)]) * 255);
            }
            else if (j <= height_block / 2) {
                //线性插值
                int num_i = (i - width_block / 2) / width_block;
                int num_j = 0;
                int num1 = num_j * block + num_i;
                int num2 = num1 + 1;
                float p = (i - (num_i*width_block + width_block / 2)) / (1.0f*width_block);
                float q = 1 - p;
                CLAHE_GO.at<uchar>(j, i) = (int)((q*C2[num1][CLAHE_GO.at<uchar>(j, i)] + p * C2[num2][CLAHE_GO.at<uchar>(j, i)]) * 255);
            }
            else if (j >= ((block - 1)*height_block + height_block / 2)) {
                //线性插值
                int num_i = (i - width_block / 2) / width_block;
                int num_j = block - 1;
                int num1 = num_j * block + num_i;
                int num2 = num1 + 1;
                float p = (i - (num_i*width_block + width_block / 2)) / (1.0f*width_block);
                float q = 1 - p;
                CLAHE_GO.at<uchar>(j, i) = (int)((q*C2[num1][CLAHE_GO.at<uchar>(j, i)] + p * C2[num2][CLAHE_GO.at<uchar>(j, i)]) * 255);
            }
            //双线性插值
            else {
                int num_i = (i - width_block / 2) / width_block;
                int num_j = (j - height_block / 2) / height_block;
                int num1 = num_j * block + num_i;
                int num2 = num1 + 1;
                int num3 = num1 + block;
                int num4 = num2 + block;
                float u = (i - (num_i*width_block + width_block / 2)) / (1.0f*width_block);
                float v = (j - (num_j*height_block + height_block / 2)) / (1.0f*height_block);
                CLAHE_GO.at<uchar>(j, i) = (int)((u*v*C2[num4][CLAHE_GO.at<uchar>(j, i)] +
                    (1 - v)*(1 - u)*C2[num1][CLAHE_GO.at<uchar>(j, i)] +
                    u * (1 - v)*C2[num2][CLAHE_GO.at<uchar>(j, i)] +
                    v * (1 - u)*C2[num3][CLAHE_GO.at<uchar>(j, i)]) * 255);
            }
            //最后这步,类似高斯平滑
            CLAHE_GO.at<uchar>(j, i) = CLAHE_GO.at<uchar>(j, i) + (CLAHE_GO.at<uchar>(j, i) << 8) + (CLAHE_GO.at<uchar>(j, i) << 16);
        }
    }
    return CLAHE_GO;
}
原文地址:https://www.cnblogs.com/hsy1941/p/11918105.html