I don't have a lot of experience in C++; I'm more of a C# guy. I'm trying to convert some Matlab image processing code to C++. I would appreciate any feedback about C++ coding conventions, which data structures to use, what kills performance, and anything which is considered to be good or bad coding style for C++. I'm kind of mixing C and C++ and C# so I wanted to get some feedback.
Preprocessor.h
#pragma once
#include <stdio.h>
#include <map>
#include <algorithm>
#include <vector>
#include "ToolBoxExports.h"
#include "PreprocessorResult.h"
using namespace std;
#include <stdint.h>
typedef enum TOOLBOX_EXPORT
{
GrRBGb = 0,
RGrGbB,
BGbGrR,
GbBRGr
} color_order;
typedef class TOOLBOX_EXPORT
{
public:
uint16_t width;
uint16_t height;
color_order order;
uint16_t* raw_data;
uint16_t bit_depth;
} bayer_raw_image;
typedef class TOOLBOX_EXPORT
{
public :
double exposure_time;
double analog_gain;
std::vector<uint16_t> black_level;
} black_level_lut;
typedef class TOOLBOX_EXPORT
{
public:
std::vector<black_level_lut*> black_level_luts;
} black_level;
class TOOLBOX_EXPORT Preprocessor
{
public:
PreprocessorResult Function1(bayer_raw_image* rawBayerImage, black_level* blackLevelDataNative, std::vector<double> saturationLevel, double analogGain, double exposureTime);
PreprocessorResult Function3b(bayer_raw_image* rawBayerImage, bayer_raw_image* colorCheckerImage, int sensorColorOrder, std::vector<double> saturationLevel);
void Process(std::vector<uint16_t>& data, int width, int height, std::vector<float>& output);
void CalculateBlackLevel(black_level* blackLevelDataNative, double analogGain, double exposureTime, double(&output)[4]);
void SeparateChannels(uint16_t* _image, std::vector<uint16_t>& gr, std::vector<uint16_t>& r, std::vector<uint16_t>& b, std::vector<uint16_t>& gb, int width, int height, int colorOrder);
void ScaleLscGrid(std::vector<float>& gr, std::vector<float>& r, std::vector<float>& b, std::vector<float>& gb, uint16_t height, uint16_t width, uint16_t desiredWidth, uint16_t desiredHeight, std::string method);
void ApplyLensShadingCorrection(std::vector<float>& floatChannel_gr, std::vector<float>& floatChannel_r, std::vector<float>& floatChannel_b, std::vector<float>& floatChannel_gb, std::vector<uint16_t>& channel_gr_cc, std::vector<uint16_t>& channel_r_cc, std::vector<uint16_t>& channel_b_cc, std::vector<uint16_t>& channel_gb_cc, uint16_t channelCCWidth, uint16_t channelCCHeight);
void CombineChannelsTo2dImage(std::vector<float>& gr, std::vector<float>& r, std::vector<float>& b, std::vector<float>& gb, int isOverride, bayer_raw_image* outputImage, std::vector<double> saturationLevel);
int MatlabRound(double numberToRound);//needs to be in a utilities project
void ShowImage(bayer_raw_image* colorCheckerImage, std::string title);
void ShowImage(std::vector<float> channel, uint16_t width, uint16_t height, std::string title);
};
Preprocessor.cpp
#include "Preprocessor.h"
#include "PreprocessorResult.h"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <array>
#include <algorithm>
PreprocessorResult Preprocessor::Function1(bayer_raw_image* rawBayerImage, black_level* blackLevelDataNative, std::vector<double> saturationLevel, double analogGain, double exposureTime)
{
if (analogGain <= 0.0)
{
throw "Analog gain must be positive";
}
if (rawBayerImage == NULL)
{
throw "Missing image";
}
if (blackLevelDataNative == NULL)
{
throw "Missing BLC data";
}
if (saturationLevel.empty())
{
throw "Missing SaturationLevel data";
}
double blackLevelOutputTable[4];
CalculateBlackLevel(blackLevelDataNative, analogGain, exposureTime, blackLevelOutputTable);
// TODO: Normalization code below has multiple bugs!
double factor0 = saturationLevel[0] / (saturationLevel[0] - blackLevelOutputTable[0]);
double factor1 = saturationLevel[1] / (saturationLevel[1] - blackLevelOutputTable[1]);
double factor2 = saturationLevel[2] / (saturationLevel[2] - blackLevelOutputTable[2]);
double factor3 = saturationLevel[3] / (saturationLevel[3] - blackLevelOutputTable[3]);
for (int i = 0; i < rawBayerImage->width* rawBayerImage->height; i++)
{
if (i % 4 == 0)
{
rawBayerImage->raw_data[i] = std::max(0.0, std::min(((rawBayerImage->raw_data[i] - blackLevelOutputTable[0]) * factor0), saturationLevel[0]));
}
if (i % 4 == 1)
{
rawBayerImage->raw_data[i] = std::max(0.0, std::min(((rawBayerImage->raw_data[i] - blackLevelOutputTable[1]) * factor1), saturationLevel[1]));
}
if (i % 4 == 2)
{
rawBayerImage->raw_data[i] = std::max(0.0, std::min(((rawBayerImage->raw_data[i] - blackLevelOutputTable[2]) * factor2), saturationLevel[2]));
}
if (i % 4 == 3)
{
rawBayerImage->raw_data[i] = std::max(0.0, std::min(((rawBayerImage->raw_data[i] - blackLevelOutputTable[3]) * factor3), saturationLevel[3]));
}
}
PreprocessorResult result;
for (int i = 0; i < 4; i++)
{
result.blackLevelGains[i] = blackLevelOutputTable[i];
}
return result;
}
PreprocessorResult Preprocessor::Function3b(bayer_raw_image* flatFieldImage, bayer_raw_image* colorCheckerImage, int sensorColorOrder, std::vector<double> saturationLevel)
{
int sizeOfChannel = (flatFieldImage->width / 2) * (flatFieldImage->height / 2);
std::vector<uint16_t> channel_r_ff(sizeOfChannel);
std::vector<uint16_t> channel_gr_ff(sizeOfChannel);
std::vector<uint16_t> channel_gb_ff(sizeOfChannel);
std::vector<uint16_t> channel_b_ff(sizeOfChannel);
std::vector<float> floatChannel_r(sizeOfChannel);
std::vector<float> floatChannel_gr(sizeOfChannel);
std::vector<float> floatChannel_gb(sizeOfChannel);
std::vector<float> floatChannel_b(sizeOfChannel);
SeparateChannels(flatFieldImage->raw_data, channel_gr_ff, channel_r_ff, channel_b_ff, channel_gb_ff, flatFieldImage->width, flatFieldImage->height, flatFieldImage->order);
int channelWidth = flatFieldImage->width / 2;
int channelHeight = flatFieldImage->height / 2;
Process(channel_gr_ff, channelWidth, channelHeight, floatChannel_gr);
Process(channel_r_ff, channelWidth, channelHeight, floatChannel_r);
Process(channel_b_ff, channelWidth, channelHeight, floatChannel_b);
Process(channel_gb_ff, channelWidth, channelHeight, floatChannel_gb);
//there is no need to preform
//grid = toolbox.bayer.ColorOrder.combineChannels(Gr, R, B, Gb, colorOrder, override);
// just have to switch the color order
std::vector<uint16_t>channel_r_cc(sizeOfChannel);
std::vector<uint16_t>channel_gr_cc(sizeOfChannel);
std::vector<uint16_t>channel_gb_cc(sizeOfChannel);
std::vector<uint16_t>channel_b_cc(sizeOfChannel);
//for debug
//ShowImage(colorCheckerImage,"before");
SeparateChannels(colorCheckerImage->raw_data, channel_gr_cc, channel_r_cc, channel_b_cc, channel_gb_cc, colorCheckerImage->width, colorCheckerImage->height, colorCheckerImage->order);
int channelCCWidth = colorCheckerImage->width / 2;
int channelCCHeight = colorCheckerImage->height / 2;
ApplyLensShadingCorrection(floatChannel_gr, floatChannel_r, floatChannel_b, floatChannel_gb, channel_gr_cc, channel_r_cc, channel_b_cc, channel_gb_cc, channelCCWidth, channelCCHeight);
//for debug
//ShowImage(floatChannel_gr,channelCCWidth,channelCCHeight, "gr");
//ShowImage(floatChannel_gb,channelCCWidth,channelCCHeight, "gb");
//ShowImage(floatChannel_b,channelCCWidth,channelCCHeight, "b");
//ShowImage(floatChannel_r,channelCCWidth,channelCCHeight, "r");
CombineChannelsTo2dImage(floatChannel_gr, floatChannel_r, floatChannel_b, floatChannel_gb, 1, colorCheckerImage, saturationLevel);
//ShowImage(colorCheckerImage,"after");
PreprocessorResult result;
return result;
}
void Preprocessor::CalculateBlackLevel(black_level* blackLevelDataNative, double analogGain, double exposureTime, double(&output)[4])
{
const int NUMBER_OF_CHANNELS = 4;
std::vector<double> exposureTimeLut;
std::vector<std::array<int, NUMBER_OF_CHANNELS> > blackLevelLut;
if (blackLevelDataNative->black_level_luts.size() == 1)
{
std::array<int, NUMBER_OF_CHANNELS> arr;
for (size_t i = 0; i < NUMBER_OF_CHANNELS; i++)
{
arr[i] = blackLevelDataNative->black_level_luts[0]->black_level[i];
}
blackLevelLut.push_back(arr);
}
else
{
double maxAnalogGain = blackLevelDataNative->black_level_luts[0]->analog_gain;
double minAnalogGain = blackLevelDataNative->black_level_luts[0]->analog_gain;
for (int num = 0; num < blackLevelDataNative->black_level_luts.size(); num++)
{
maxAnalogGain = std::max(maxAnalogGain, blackLevelDataNative->black_level_luts[num]->analog_gain);
minAnalogGain = std::min(minAnalogGain, blackLevelDataNative->black_level_luts[num]->analog_gain);
}
if (analogGain >= maxAnalogGain || analogGain <= minAnalogGain)
{
for (int k = 0; k < blackLevelDataNative->black_level_luts.size(); k++)
{
//find which points you need to interpolate
if (analogGain >= blackLevelDataNative->black_level_luts[k]->analog_gain && analogGain <= blackLevelDataNative->black_level_luts[k + 1]->analog_gain)
{
std::array<int, NUMBER_OF_CHANNELS> arr;
for (int ch = 0; ch < NUMBER_OF_CHANNELS; ch++)
{
//y = y0 + (y1-y0)*(x-x0)/(x1-x0);
double y0 = blackLevelDataNative->black_level_luts[k]->black_level[ch];
double y1 = blackLevelDataNative->black_level_luts[k + 1]->black_level[ch];
double x = analogGain;
double x0 = blackLevelDataNative->black_level_luts[k]->analog_gain;
double x1 = blackLevelDataNative->black_level_luts[k + 1]->analog_gain;
arr[ch] = y0 + (y1 - y0)*(x - x0) / (x1 - x0);
}
blackLevelLut.push_back(arr);
//if the vector does not contains the exposure, add if to the vector
if (std::find(exposureTimeLut.begin(), exposureTimeLut.end(), blackLevelDataNative->black_level_luts[k]->exposure_time) == exposureTimeLut.end())
{
exposureTimeLut.push_back(blackLevelDataNative->black_level_luts[k]->exposure_time);
}
}
}
}
else //extrapolate nearest neighbor
{
for (int k = 0; k < blackLevelDataNative->black_level_luts.size(); k++)
{
if (analogGain > maxAnalogGain)
{
if (blackLevelDataNative->black_level_luts[k]->analog_gain == maxAnalogGain)
{
std::array<int, NUMBER_OF_CHANNELS> arr;
for (int ch = 0; ch < NUMBER_OF_CHANNELS; ch++)
{
arr[ch] = blackLevelDataNative->black_level_luts[k]->black_level[ch];
}
blackLevelLut.push_back(arr);
//if the vector does not contains the exposure, add if to the vector
if (std::find(exposureTimeLut.begin(), exposureTimeLut.end(), blackLevelDataNative->black_level_luts[k]->exposure_time) == exposureTimeLut.end())
{
exposureTimeLut.push_back(blackLevelDataNative->black_level_luts[k]->exposure_time);
}
}
}
else //analogGain < minAnalogGain
{
if (blackLevelDataNative->black_level_luts[k]->analog_gain == minAnalogGain)
{
std::array<int, NUMBER_OF_CHANNELS> arr;
for (int ch = 0; ch < NUMBER_OF_CHANNELS; ch++)
{
arr[ch] = arr[ch] = blackLevelDataNative->black_level_luts[k]->black_level[ch];
}
blackLevelLut.push_back(arr);
//if the vector does not contains the exposure, add if to the vector
if (std::find(exposureTimeLut.begin(), exposureTimeLut.end(), blackLevelDataNative->black_level_luts[k]->exposure_time) == exposureTimeLut.end())
{
exposureTimeLut.push_back(blackLevelDataNative->black_level_luts[k]->exposure_time);
}
}
}
}
}
}
if (exposureTimeLut.size() == 1)
{
for (int i = 0; i < NUMBER_OF_CHANNELS; i++)
{
output[i] = blackLevelLut[0][i];
}
return;
}
else
{
std::vector<double>::iterator iterMax = std::max_element(exposureTimeLut.begin(), exposureTimeLut.end());
std::vector<double>::iterator iterMin = std::min_element(exposureTimeLut.begin(), exposureTimeLut.end());
for (int k = 0; k < exposureTimeLut.size(); k++)
{
if (exposureTime <= *iterMax && exposureTime >= *iterMin) //interpolate
{
//find which points you need to interpolate
if (exposureTime >= exposureTimeLut[k] && exposureTime <= exposureTimeLut[k + 1])
{
for (int ch = 0; ch < NUMBER_OF_CHANNELS; ch++)
{
//y = y0 + (y1-y0)*(x-x0)/(x1-x0);
double y0 = blackLevelLut[k][ch];
double y1 = blackLevelLut[k + 1][ch];
double x = exposureTime;
double x0 = exposureTimeLut[k];
double x1 = exposureTimeLut[k + 1];
output[ch] = y0 + (y1 - y0)*(x - x0) / (x1 - x0);
}
return; //break the loop
}
}
else //extrapolate nearest neighbor
{
for (int ch = 0; ch < NUMBER_OF_CHANNELS; ch++)
{
if (exposureTime > *iterMax)
{
output[ch] = blackLevelLut[exposureTimeLut.size() - 1][ch];
}
else
{
output[ch] = blackLevelLut[0][ch];
}
}
return;
}
}
}
}
void Preprocessor::SeparateChannels(uint16_t* _image, std::vector<uint16_t>& gr, std::vector<uint16_t>& r, std::vector<uint16_t>& b, std::vector<uint16_t>& gb, int width, int height, int colorOrder)
{
//swith case the color Order
int counter_R = 0;
int counter_GR = 0;
int counter_GB = 0;
int counter_B = 0;
switch (colorOrder)
{
//grbg
case 0:
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
if (i % 2 == 0 && j % 2 == 0)
{
gr[counter_GR] = _image[i*width + j];
counter_GR++;
}
else if (i % 2 == 0 && j % 2 == 1)
{
r[counter_R] = _image[i*width + j];
counter_R++;
}
else if (i % 2 == 1 && j % 2 == 0)
{
b[counter_B] = _image[i*width + j];
counter_B++;
}
else if (i % 2 == 1 && j % 2 == 1)
{
gb[counter_GB] = _image[i*width + j];
counter_GB++;
}
}
}
break;
//rggb
case 1:
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
if (i % 2 == 0 && j % 2 == 0)
{
r[counter_R] = _image[i*width + j];
counter_R++;
}
else if (i % 2 == 0 && j % 2 == 1)
{
gr[counter_GR] = _image[i*width + j];
counter_GR++;
}
else if (i % 2 == 1 && j % 2 == 0)
{
gb[counter_GB] = _image[i*width + j];
counter_GB++;
}
else if (i % 2 == 1 && j % 2 == 1)
{
b[counter_B] = _image[i*width + j];
counter_B++;
}
}
}
break;
//bggr
case 2:
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
if (i % 2 == 0 && j % 2 == 0)
{
b[counter_B] = _image[i*width + j];
counter_B++;
}
else if (i % 2 == 0 && j % 2 == 1)
{
gb[counter_GB] = _image[i*width + j];
counter_GB++;
}
else if (i % 2 == 1 && j % 2 == 0)
{
gr[counter_GR] = _image[i*width + j];
counter_GR++;
}
else if (i % 2 == 1 && j % 2 == 1)
{
r[counter_R] = _image[i*width + j];
counter_R++;
}
}
}
break;
//gbrg
case 3:
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
if (i % 2 == 0 && j % 2 == 0)
{
gb[counter_GB] = _image[i*width + j];
counter_GB++;
}
else if (i % 2 == 0 && j % 2 == 1)
{
b[counter_B] = _image[i*width + j];
counter_B++;
}
else if (i % 2 == 1 && j % 2 == 0)
{
r[counter_R] = _image[i*width + j];
counter_R++;
}
else if (i % 2 == 1 && j % 2 == 1)
{
gr[counter_GR] = _image[i*width + j];
counter_GR++;
}
}
}
break;
}
}
//function data = process(data)
// data = medfilt2(data, [7 7], 'symmetric');
// mask = fspecial('gaussian', [35 35], 12);
// data = imfilter(data, mask, 'replicate', 'same');
// maximum = max(data(:));
// data = 1 ./ ( data/maximum );
// data(data > 10) = 16;
//end
void Preprocessor::Process(std::vector<uint16_t>& data, int width, int height, std::vector<float>& output)
{
//the median filter removes noises like salt & pepper// defect pixel correction
//Gaussion filter smooths the image by blurring it - remember this is a flat field image
cv::Mat median = cv::Mat::zeros(height, width, CV_32F);
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
median.at<float>(i, j) = data[i*width + j];
}
}
cv::medianBlur(median, median, 5);//TODO should be 7x7 kernel size
cv::GaussianBlur(median, median, cv::Size(35, 35), 12.0, cv::BORDER_REPLICATE);
double min, max;
cv::minMaxLoc(median, &min, &max);
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
output[i*width + j] = 1.0 / (median.at<float>(i, j) / max);
if (output[i*width + j] > 10)
{
output[i*width + j] = 16;
}
}
}
}
void Preprocessor::CombineChannelsTo2dImage(std::vector<float>& gr, std::vector<float>& r, std::vector<float>& b, std::vector<float>& gb, int isOverride, bayer_raw_image* outputImage, std::vector<double> saturationLevel)
{
//swith case the color Order
int counter_R = 0;
int counter_GR = 0;
int counter_GB = 0;
int counter_B = 0;
//this is the avoid redundent casting
float saturationLevel0 = saturationLevel[0];
float saturationLevel1 = saturationLevel[1];
float saturationLevel2 = saturationLevel[2];
float saturationLevel3 = saturationLevel[3];
float tempCalc;
//there are 2 options 4d or 2d(image)
if (isOverride == 1)
{
switch (outputImage->order)
{
//grbg
case 0:
for (int i = 0; i < outputImage->height; i++)
{
for (int j = 0; j < outputImage->width; j++)
{
if (i % 2 == 0 && j % 2 == 0)
{
tempCalc = std::min(gr[counter_GR], saturationLevel0);
tempCalc = MatlabRound(tempCalc);
tempCalc = std::max(tempCalc, 0.0f);
outputImage->raw_data[i*outputImage->width + j] = tempCalc;
counter_GR++;
}
else if (i % 2 == 0 && j % 2 == 1)
{
tempCalc = std::min(r[counter_R], saturationLevel1);
tempCalc = MatlabRound(tempCalc);
tempCalc = std::max(tempCalc, 0.0f);
outputImage->raw_data[i*outputImage->width + j] = tempCalc;
counter_R++;
}
else if (i % 2 == 1 && j % 2 == 0)
{
tempCalc = std::min(b[counter_B], saturationLevel2);
tempCalc = MatlabRound(tempCalc);
tempCalc = std::max(tempCalc, 0.0f);
outputImage->raw_data[i*outputImage->width + j] = tempCalc;
counter_B++;
}
else if (i % 2 == 1 && j % 2 == 1)
{
tempCalc = std::min(gb[counter_GB], saturationLevel3);
tempCalc = MatlabRound(tempCalc);
tempCalc = std::max(tempCalc, 0.0f);
outputImage->raw_data[i*outputImage->width + j] = tempCalc;
counter_GB++;
}
}
}
break;
//rggb
case 1:
break;
//bggr
case 2:
break;
//gbrg
case 3:
break;
default:
break;
}
}
else
{
//need to implement the no override
}
}
void Preprocessor::ScaleLscGrid(std::vector<float>& gr, std::vector<float>& r, std::vector<float>& b, std::vector<float>& gb, uint16_t height, uint16_t width, uint16_t desiredWidth, uint16_t desiredHeight, std::string method = "cubic")
{
if (height == desiredWidth && width == desiredWidth)
{
return;
}
double scaleLimit = 10.5;
double scaleFactor = floor(scaleLimit);
double widthTemp;
double heightTemp;
if ((desiredWidth / (double)width > scaleLimit) || desiredHeight / (double)height > scaleLimit)
{
widthTemp = (width * scaleFactor) + 1;
heightTemp = (height * scaleFactor) + 1;
//to do Grid...
}
}
void Preprocessor::ApplyLensShadingCorrection(std::vector<float>& floatChannel_gr, std::vector<float>& floatChannel_r, std::vector<float>& floatChannel_b, std::vector<float>& floatChannel_gb,
std::vector<uint16_t>& channel_gr_cc, std::vector<uint16_t>& channel_r_cc, std::vector<uint16_t>& channel_b_cc, std::vector<uint16_t>& channel_gb_cc, uint16_t channelCCWidth, uint16_t channelCCHeight)
{
for (int i = 0; i < channelCCHeight; i++)
{
for (int j = 0; j < channelCCWidth; j++)
{
floatChannel_gr[i*channelCCWidth + j] = floatChannel_gr[i*channelCCWidth + j] * channel_gr_cc[i*channelCCWidth + j];
floatChannel_r[i*channelCCWidth + j] = floatChannel_r[i*channelCCWidth + j] * channel_r_cc[i*channelCCWidth + j];
floatChannel_b[i*channelCCWidth + j] = floatChannel_b[i*channelCCWidth + j] * channel_b_cc[i*channelCCWidth + j];
floatChannel_gb[i*channelCCWidth + j] = floatChannel_gb[i*channelCCWidth + j] * channel_gb_cc[i*channelCCWidth + j];
}
}
}
int Preprocessor::MatlabRound(double numberToRound)
{
return (int)floor(numberToRound + 0.5);
}
void Preprocessor::ShowImage(bayer_raw_image* colorCheckerImage, std::string title)
{
cv::Mat image(colorCheckerImage->height, colorCheckerImage->width, CV_32F);
for (int i = 0; i < colorCheckerImage->height; i++)
{
for (int j = 0; j < colorCheckerImage->width; j++)
{
image.at<float>(i, j) = colorCheckerImage->raw_data[i*colorCheckerImage->width + j] / 1023.0;
}
}
/*cv::imshow(title, image);
cv::waitKey(0);*/
int sizeOfChannel = (colorCheckerImage->width / 2) * (colorCheckerImage->height / 2);
std::vector<uint16_t> channel_r_cc(sizeOfChannel);
std::vector<uint16_t> channel_gr_cc(sizeOfChannel);
std::vector<uint16_t> channel_gb_cc(sizeOfChannel);
std::vector<uint16_t> channel_b_cc(sizeOfChannel);
//for debug
SeparateChannels(colorCheckerImage->raw_data, channel_gr_cc, channel_r_cc, channel_b_cc, channel_gb_cc, colorCheckerImage->width, colorCheckerImage->height, colorCheckerImage->order);
cv::Mat src = cv::Mat::zeros(colorCheckerImage->height / 2, colorCheckerImage->width / 2, CV_32FC3);
for (int w = 0; w < colorCheckerImage->width / 2; w++)
{
for (int h = 0; h < colorCheckerImage->height / 2; h++)
{
src.at<cv::Vec3f>(h, w)[0] = channel_b_cc[h*(colorCheckerImage->width / 2) + w];
src.at<cv::Vec3f>(h, w)[1] = (channel_gr_cc[h*(colorCheckerImage->width / 2) + w] + channel_gb_cc[h*(colorCheckerImage->width / 2) + w]) / 2.0;
src.at<cv::Vec3f>(h, w)[2] = channel_r_cc[h*(colorCheckerImage->width / 2) + w];
}
}
src = src / 1023.0;
cv::imshow(title + " in rgb", src);
cv::waitKey(0);
}
void Preprocessor::ShowImage(std::vector<float> channel, uint16_t width, uint16_t height, std::string title)
{
cv::Mat image(height, width, CV_32F);
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
image.at<float>(i, j) = channel[i*width + j] / 1023.0;
}
}
cv::imshow(title, image);
cv::waitKey(0);
}
static uint16_t Clip(uint16_t data, uint16_t min, uint16_t max)
{
return std::min(std::max(data, min), max);
}