#include <opencv2/opencv.hpp>
#include <iostream>


using namespace cv;


class Level {
public:
	int   Shadow;  //输入色阶黑点值
	float Midtones; //输入色阶灰点值(注意是浮点数)
	int   Highlight; //输入色阶白点值

	int   OutputShadow; //输出色阶黑点值
	int   OutputHighlight; //输出色阶白点值


    Level() {};
    virtual ~Level() {};

	bool createColorTable(uchar* colorTable)
	{
        int diff = (int)(Highlight - Shadow);
        int outDiff = (int)(OutputHighlight - OutputShadow);

        if (!((Highlight <= 255 && diff <= 255 && diff >= 2) ||
            (OutputShadow <= 255 && OutputHighlight <= 255 && outDiff < 255) ||
            (!(Midtones > 9.99 && Midtones > 0.1) && Midtones != 1.0)))
            return false;

        double coef = 255.0 / diff;
        double outCoef = outDiff / 255.0;
        double exponent = 1.0 / Midtones;

        for (int i = 0; i < 256; i++)
        {
            int v;
            // calculate black field and white field of input level
            if (colorTable[i] <= (uchar)Shadow) {
                v = 0;
            }
            else {
                v = (int)((colorTable[i] - Shadow) * coef + 0.5);
                if (v > 255) v = 255;
            }
            // calculate midtone field of input level
            v = (int)(pow(v / 255.0, exponent) * 255.0 + 0.5);
            // calculate output level
            colorTable[i] = (uchar)(v * outCoef + OutputShadow + 0.5);
        }

        return true;
	}
	
};


class Levels {
protected:
    bool createColorTables(uchar colorTables[][256])
    {
        bool result = false;
        int i, j;

        //initialize color table
        for (i = 0; i < 3; i++) {
            for (j = 0; j < 256; j++)
                colorTables[i][j] = (uchar)j;
        }

        //create color table for each channel
        //result = BlueChannel.createColorTable(colorTables[0]);
        //result = GreenChannel.createColorTable(colorTables[1]);
        //result = RedChannel.createColorTable(colorTables[2]);

        result = RGBChannel.createColorTable(colorTables[0]);
        result = RGBChannel.createColorTable(colorTables[1]);
        result = RGBChannel.createColorTable(colorTables[2]);

        return result;
    
    }

public:
	Level RGBChannel;  //RGB整体调整
	//Level RedChannel;  //红色通道
	//Level GreenChannel; //绿色通道
	//Level BlueChannel; //蓝色通道

    Levels() {};
    virtual ~Levels() {};

    //实施色阶调整
    int adjust(InputArray src, OutputArray dst) 
    {
        Mat input = src.getMat();
        if (input.empty()) {
            return -1;
        }

        dst.create(src.size(), src.type());
        Mat output = dst.getMat();

        const uchar* in;
        uchar* out;
        int width = input.cols;
        int height = input.rows;
        int channels = input.channels();

        uchar colorTables[3][256];

        //create color tables
        if (!createColorTables(colorTables)) {
            //error create color table"
            return 1;
        }

        //adjust each pixel
#ifdef HAVE_OPENMP
#pragma omp parallel for
#endif
        for (int y = 0; y < height; y++) {
            in = input.ptr<uchar>(y);
            out = output.ptr<uchar>(y);
            for (int x = 0; x < width; x++) {
                for (int c = 0; c < 3; c++) {
                    *out++ = colorTables[c][*in++];
                }
                for (int c = 0; c < channels - 3; c++) {
                    *out++ = *in++;
                }
            }
        }

        return 0;
    }

    
};


void colorClassAdjust(Mat img, Mat& dst, int shadow = 202, int midtones = 100, int highlight = 255);



int main()
{

    Mat src;
    //src = imread("E:\\photo\\xuxian.jpg");
    /*if (!src.data)
    {
        std::cout << "error read image" << std::endl;
        return -1;
    }*/
    VideoCapture capture("G:\\shared\\CarShowRecorder1\\RecordVideo3\\CARSHOW_VID_20210830_145444.mp4");              //改用自己的视频地址
    if (!capture.isOpened())
    {
        std::cout << "no pic..." << std::endl;
        return -1;
    }
    namedWindow("src", 1);
    
    //Levels levels;
    //Level* currentChannel = NULL;
    //currentChannel = &levels.RGBChannel;
    //if (currentChannel == NULL)
    //    return -1;
    //// 给色阶的黑点、白点、灰度赋值
    //int   Shadow = 210;
    //int   Midtones = 100;
    //int   Highlight = 255;
    //int   OutputShadow = 0;
    //int   OutputHighlight = 255;

    //currentChannel->Shadow = Shadow;
    //currentChannel->Midtones = Midtones / 100.0;
    //currentChannel->Highlight = Highlight;
    //currentChannel->OutputShadow = OutputShadow;
    //currentChannel->OutputHighlight = OutputHighlight;

    for (;;)
    {
        capture.read(src);
        imshow("src", src);
        Mat dst;
        //levels.adjust(src, dst);
        colorClassAdjust(src, dst);
        imshow("dst", dst);
        if (waitKey(30) > 0)
            break;
    }
    

    waitKey(0);
    return 0;
}

void colorClassAdjust(Mat img, Mat& dst, int shadow, int midtones, int highlight)
{
    Levels levels;
    Level* currentChannel = NULL;
    currentChannel = &levels.RGBChannel;
    if (currentChannel == NULL)
        return ;
    // 给色阶的黑点、白点、灰度赋值
    //int   Shadow = 210;
    //int   Midtones = 100;
    //int   Highlight = 255;
    //int   OutputShadow = 0;
    //int   OutputHighlight = 255;

    currentChannel->Shadow = shadow;
    currentChannel->Midtones = midtones / 100.0;
    currentChannel->Highlight = highlight;
    currentChannel->OutputShadow = 0;
    currentChannel->OutputHighlight = 255;

    levels.adjust(img, dst);

}

作用是为了提高每帧图片的对比度,需要注意的是:我已经将整个功能封装到 colorClassAdjust()方法中, 直接调用这个方法就可以, 另外,可以自行修改需要输出的OutputShadow(输出黑点)、OutputHighlight(输出高光)值
具体参数功能作用,代码注释有,如有问题,欢迎留言交流。

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐