1.添加答题卡除红算法;

2.更新最新的二值化算法;
This commit is contained in:
lovelyyoung 2020-06-23 17:19:49 +08:00
parent d6b74c6807
commit cc07cedfbf
7 changed files with 348 additions and 499 deletions

View File

@ -1,366 +1,5 @@
//#include "ImageApplyBWBinaray.h"
//
//CImageApplyBWBinaray::CImageApplyBWBinaray(ThresholdType type, int threshold, int blockSize, int constant)
// : m_threshold(threshold)
// , m_type(type)
// , m_blockSize(blockSize)
// , m_constant(constant)
// , m_table(new uchar[256])
//{
// memset(m_table, 255, 256);
// memset(m_table, 0, static_cast<size_t>(m_threshold));
//}
//
//CImageApplyBWBinaray::CImageApplyBWBinaray()
// : m_threshold(180)
// , m_type(ThresholdType::THRESH_BINARY)
// , m_blockSize(25)
// , m_constant(5)
// , m_table(new uchar[256])
//{
// memset(m_table, 255, 256);
// memset(m_table, 0, static_cast<size_t>(m_threshold));
//}
//
//
//CImageApplyBWBinaray::~CImageApplyBWBinaray(void)
//{
// delete[] m_table;
//}
//
//void CImageApplyBWBinaray::apply(cv::Mat& pDib,int side)
//{
//#ifdef LOG
// FileTools::write_log("imgprc.txt", "enter CImageApplyBWBinaray apply");
//#endif // LOG
// if (pDib.empty())
// {
//#ifdef LOG
// FileTools::write_log("imgprc.txt", "exit CImageApplyBWBinaray apply");
//#endif // LOG
// return;
// }
//
// if (pDib.channels() == 3)
// cv::cvtColor(pDib, pDib, cv::COLOR_BGR2GRAY);
//
// switch (m_type)
// {
// case ThresholdType::THRESH_BINARY:
// //cv::threshold(pDib, pDib, m_threshold, 255, CV_THRESH_BINARY);
// cv::adaptiveThreshold(pDib, pDib, 255.0, cv::ADAPTIVE_THRESH_GAUSSIAN_C, cv::THRESH_BINARY, 91, 41);
// break;
// case ThresholdType::THRESH_OTSU:
// cv::threshold(pDib, pDib, m_threshold, 255, CV_THRESH_OTSU);
// break;
// case ThresholdType::ADAPTIVE_GAUSSIAN:
// cv::adaptiveThreshold(pDib, pDib, 255, cv::ADAPTIVE_THRESH_GAUSSIAN_C, CV_THRESH_BINARY, m_blockSize, m_constant);
// break;
// case ThresholdType::ADAPTIVE_MEAN:
// cv::adaptiveThreshold(pDib, pDib, 255, cv::ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY, m_blockSize, m_constant);
// break;
// case ThresholdType::ERROR_DIFFUSION:
// errorDiffuse(pDib);
// break;
// default:
// break;
// }
//
//#ifdef LOG
// FileTools::write_log("imgprc.txt", "exit CImageApplyBWBinaray apply");
//#endif // LOG
//}
//
//void CImageApplyBWBinaray::apply(std::vector<cv::Mat>& mats, bool isTwoSide)
//{
// if (mats.empty()) return;
//
// if (!mats[0].empty()) {
// apply(mats[0], 0);
// }
//
//
// if (isTwoSide && mats.size() > 1) {
// if (!mats[1].empty())
// apply(mats[1], 1);
// }
//}
//
//void CImageApplyBWBinaray::errorDiffuse(cv::Mat & image)
//{
// if (image.rows < 3 || image.cols < 3)
// {
// cv::threshold(image, image, m_threshold, 255, CV_THRESH_BINARY);
// return;
// }
//
// cv::Mat dst;
// image.convertTo(dst, CV_16S);
//
// size_t rows = static_cast<size_t>(image.rows) - 1;
// size_t cols = static_cast<size_t>(image.cols) - 1;
//
// short** pixels_dst = new short*[static_cast<size_t>(image.rows)];
// for (int i = 0; i < image.rows; i++)
// pixels_dst[i] = reinterpret_cast<short*>(dst.data + i * static_cast<int>(dst.step));
//
// short error;
// for (size_t y = 0; y < rows; y++)
// for (size_t x = 1; x < cols; x++)
// {
// short dstPix = pixels_dst[y][x];
// if (dstPix >= m_threshold)
// {
// pixels_dst[y][x] = 255;
// error = dstPix - 255;
// }
// else
// {
// pixels_dst[y][x] = 0;
// error = dstPix;
// }
//
// pixels_dst[y][x + 1] += error * 7 / 16;
// pixels_dst[y + 1][x - 1] += error * 3 / 16;
// pixels_dst[y + 1][x] += error * 5 / 16;
// pixels_dst[y + 1][x + 1] += error * 1 / 16;
// }
// image.release();
// dst.convertTo(image, CV_8U);
//
// rows++;
// uchar* ptr = image.data;
// size_t step = image.step;
// size_t offset;
// for (size_t y = 0; y < rows; y++)
// {
// offset = y * step;
// ptr[offset] = m_table[ptr[offset]];
// offset += cols;
// ptr[offset] = m_table[ptr[offset]];
// }
//
// cols++;
// ptr = image.data + step * (rows - 1);
// for (size_t x = 0; x < cols; x++)
// ptr[x] = m_table[ptr[x]];
//
// delete[] pixels_dst;
//}
#include "ImageApplyBWBinaray.h"
#include "ImageProcess_Public.h"
#include "StopWatch.h"
#include "filetools.h"
typedef struct image_info
{
int32_t width;
int32_t height;
uint8_t* data;
}ImageInfo;
void updataIntergralImg(const uint8_t* const imgData, uint32_t* integralImg, const int32_t& width, const int32_t& height)
{
// create the integral image
//积分图像将窗口内像素值和计算时间由二阶转为常量,窗口越大,效果越明显
uint32_t sum = 0;
int32_t i, j;
const uint32_t* img = (uint32_t*)imgData;
uint32_t* interImgTmp = integralImg;
uint32_t tmp = 0;
for (i = 0; i < width; i += 4)
{
tmp = *img;
sum += tmp & 0x000000ff;//unportble
interImgTmp[0] = sum;
interImgTmp++;
sum += (tmp >> 8) & 0x000000ff;
interImgTmp[0] = sum;
interImgTmp++;
sum += (tmp >> 16) & 0x000000ff;
interImgTmp[0] = sum;
interImgTmp++;
sum += (tmp >> 24) & 0x000000ff;
interImgTmp[0] = sum;
interImgTmp++;
img++;
}
for (i = 1; i < height; ++i)
{
sum = 0;
for (j = 0; j < width; j += 4)
{
tmp = *img;
sum += tmp & 0x000000ff;
interImgTmp[0] = sum + interImgTmp[-width];
interImgTmp++;
sum += (tmp >> 8) & 0x000000ff;
interImgTmp[0] = sum + interImgTmp[-width];
interImgTmp++;
sum += (tmp >> 16) & 0x000000ff;
interImgTmp[0] = sum + interImgTmp[-width];
interImgTmp++;
sum += (tmp >> 24) & 0x000000ff;
interImgTmp[0] = sum + interImgTmp[-width];
interImgTmp++;
img++;
}
}
}
void threshold(ImageInfo& image_src, uint8_t thre)
{
uint8_t table[256];
memset(table, 0, thre);
memset(table + thre, 255, 256 - thre);
int32_t size = image_src.width * image_src.height;
uint8_t* ptr = image_src.data;
for (int32_t i = 0; i < size; i++)
{
ptr[i] = table[ptr[i]];
}
}
void adaptivethresh(ImageInfo& image_src, const uint8_t& lowThr, const uint8_t& upThr, const uint8_t& init_threshold)
{
//基本原理参见welner自适应阈值算法修改部分为将四个边界事先计算中心部分单独计算所有魔数为经验值
const uint8_t thresh = __min(init_threshold, 100);
uint8_t S = 17;
unsigned short T = 100 - thresh;
T = (unsigned short)((float)T * 10.24);
unsigned short i, j;
uint32_t sum = 0;
unsigned short count = 0;
int16_t x1, y1, x2, y2;
const uint8_t s2 = S >> 1;
uint8_t* pointer = image_src.data;
//pointer = image_src;
const int32_t width = image_src.width;
const int32_t height = image_src.height;
uint32_t* integralImg = new uint32_t[width * height];//积分图,用于自适应二值算法
updataIntergralImg(image_src.data, integralImg, width, height);
uint8_t t = 0;
ImageInfo img_up_dwon;
img_up_dwon.data = pointer;
img_up_dwon.width = width;
img_up_dwon.height = s2 + 1;
threshold(img_up_dwon, init_threshold);
pointer = image_src.data;
pointer += (height - s2) * width;
img_up_dwon.data = pointer;
img_up_dwon.width = width;
img_up_dwon.height = s2;
threshold(img_up_dwon, init_threshold);
pointer = image_src.data + (s2 + 1) * width;
for (i = 0; i <= s2; ++i)
{
for (j = s2 + 1; j < height - s2; ++j)
{
if (pointer[0] < init_threshold)
{
pointer[0] = 0;
}
else
{
pointer[0] = 255;
}
pointer += width;
}
pointer = image_src.data + (s2 + 1) * width + i + 1;
}
pointer = image_src.data + (s2 + 1) * width + (width - s2);
unsigned short ii = 1;
for (i = width - s2; i < width; ++i)
{
for (j = s2 + 1; j < height - s2; ++j)
{
if (pointer[0] < init_threshold)
{
pointer[0] = 0;
}
else
{
pointer[0] = 255;
}
pointer += width;
}
pointer = image_src.data + (s2 + 1) * width + (width - s2) + ii;
ii++;
}
///center part
unsigned short ww = width - s2 - s2 - 1;
unsigned short hh = height - s2 - s2 - 1;
uint8_t gap = width - ww;
count = (s2 << 1) + 1;
count *= count;
const uint32_t factor = count * 100 / (100 - 50);
uint32_t* plt;
uint32_t* prt;
uint32_t* plb;
uint32_t* prb;
plt = integralImg;
prt = plt + (s2 << 1) + 1;
plb = plt + ((s2 << 1) + 1) * width;
prb = prt + ((s2 << 1) + 1) * width;
pointer = image_src.data + (s2 + 1) * width + s2 + 1;
for (i = 0; i < hh; ++i)
{
for (j = 0; j < ww; j++)
{
if (/*expected_true(*/*pointer >= upThr/*)*/)
{
*pointer = 255;
}
else if (*pointer < lowThr)
{
*pointer = 0;
}
else
{
sum = *prb - *prt - *plb + *plt;
t = *pointer;
if (/*expected_false(*/t * factor <= sum/*)*/)
*pointer = 0;
else
*pointer = 255;
}
plt++;
prt++;
plb++;
prb++;
pointer++;
}
plt += gap;
prt += gap;
plb += gap;
prb += gap;
pointer += width - ww;
}
delete[]integralImg;
}
#include "ImageApplyDetachNoise.h"
CImageApplyBWBinaray::CImageApplyBWBinaray(ThresholdType type, int threshold, int blockSize, int constant)
: m_threshold(threshold)
@ -374,7 +13,7 @@ CImageApplyBWBinaray::CImageApplyBWBinaray(ThresholdType type, int threshold, in
}
CImageApplyBWBinaray::CImageApplyBWBinaray()
: m_threshold(160)
: m_threshold(120)
, m_type(ThresholdType::THRESH_BINARY)
, m_blockSize(25)
, m_constant(5)
@ -384,7 +23,6 @@ CImageApplyBWBinaray::CImageApplyBWBinaray()
memset(m_table, 0, static_cast<size_t>(m_threshold));
}
CImageApplyBWBinaray::~CImageApplyBWBinaray(void)
{
delete[] m_table;
@ -398,42 +36,19 @@ void CImageApplyBWBinaray::apply(cv::Mat& pDib, int side)
if (pDib.channels() == 3)
cv::cvtColor(pDib, pDib, cv::COLOR_BGR2GRAY);
cv::Mat integ;
int blockSize = 31;//ÁÚÓò³ß´ç
int threshold = 21;
int low = 110;
int up = 220;
int halfSize = blockSize / 2;
int square_blockSize = blockSize * blockSize;
CImageApplyDetachNoise noise(6);
switch (m_type)
{
case ThresholdType::THRESH_BINARY:
{
#if 0
StopWatch sw;
float ksize = 9.0f;
float other = (1.0f - ksize) / 4.0f;
float kernel_data[] = { 0, other, 0, other, ksize, other, 0, other, 0 };
cv::Mat kernel(3, 3, CV_32FC1, kernel_data);
cv::filter2D(pDib, pDib, pDib.depth(), kernel);
FileTools::write_log("E:\\Users\\huago\\Desktop\\2.txt", "filter2D: " + std::to_string(sw.elapsed_ms()));
sw.reset();
cv::adaptiveThreshold(pDib, pDib, 255, cv::ADAPTIVE_THRESH_GAUSSIAN_C, CV_THRESH_BINARY, 91, 21);
FileTools::write_log("E:\\Users\\huago\\Desktop\\2.txt", "adaptiveThreshold: " + std::to_string(sw.elapsed_ms()));
//cv::Mat mask = pDib.clone();
//std::vector<std::vector<cv::Point>> contours;
//std::vector<cv::Vec4i> h;
//hg::findContours(mask, contours, h);
//mask.release();
//for (const std::vector<cv::Point>& contour : contours)
// if (contourArea(contour) < 6)
// fillConvexPoly(pDib, contour, cv::Scalar(255));
#endif
//StopWatch sw;
cv::Mat integ;
cv::integral(pDib, integ, CV_32S);
int blockSize = 31;//邻域尺寸
int threshold = 21;
int low = 110;
int up = 220;
int halfSize = blockSize / 2;
int square_block = blockSize * blockSize;
for (int j = halfSize; j < integ.rows - halfSize - 1; j++)
{
uchar* data = pDib.ptr<uchar>(j);
@ -441,35 +56,19 @@ void CImageApplyBWBinaray::apply(cv::Mat& pDib, int side)
int* idata2 = integ.ptr<int>(j + halfSize + 1);
for (int i = halfSize; i < integ.cols - halfSize - 1; i++)
{
int sum = (idata2[i + halfSize + 1] - idata2[i - halfSize] - idata1[i + halfSize + 1] + idata1[i - halfSize]) / square_block;
if (data[i] < low) data[i] = 0;
else if (data[i] > up) data[i] = 255;
else
{
if (data[i] < (sum - threshold))
data[i] = 0;
else
data[i] = 255;
}
data[i] = data[i] < ((idata2[i + halfSize + 1] - idata2[i - halfSize] - idata1[i + halfSize + 1] + idata1[i - halfSize]) / square_blockSize - threshold) ? 0 : 255;
}
}
cv::threshold(pDib(cv::Rect(0, 0, halfSize, pDib.rows)), pDib(cv::Rect(0, 0, halfSize, pDib.rows)), m_threshold, 255, cv::THRESH_BINARY);
cv::threshold(pDib(cv::Rect(pDib.cols - halfSize, 0, halfSize, pDib.rows)), pDib(cv::Rect(pDib.cols - halfSize, 0, halfSize, pDib.rows)), m_threshold, 255, cv::THRESH_BINARY);
cv::threshold(pDib(cv::Rect(0, 0, pDib.cols, halfSize)), pDib(cv::Rect(0, 0, pDib.cols, halfSize)), m_threshold, 255, cv::THRESH_BINARY);
cv::threshold(pDib(cv::Rect(0, pDib.rows - halfSize, pDib.cols, halfSize)), pDib(cv::Rect(0, pDib.rows - halfSize, pDib.cols, halfSize)), m_threshold, 255, cv::THRESH_BINARY);
cv::Mat mask = pDib.clone();
std::vector<std::vector<cv::Point>> contours;
std::vector<cv::Vec4i> h;
hg::findContours(mask, contours, h);
mask.release();
for (const std::vector<cv::Point>& contour : contours)
if (contourArea(contour) < 6)
fillConvexPoly(pDib, contour, cv::Scalar(255));
//FileTools::write_log("E:\\Users\\huago\\Desktop\\2.txt", "THRESH_BINARY eplsed: " + std::to_string(sw.elapsed_ms()));
//cv::threshold(pDib, pDib, m_threshold, 255, CV_THRESH_OTSU);
noise.apply(pDib, side);
break;
}
case ThresholdType::THRESH_OTSU:
cv::threshold(pDib, pDib, m_threshold, 255, CV_THRESH_OTSU);
break;
@ -538,9 +137,9 @@ void CImageApplyBWBinaray::errorDiffuse(cv::Mat& image)
error = dstPix;
}
pixels_dst[y][x + 1] += error * 7 / 16;
pixels_dst[y + 1][x - 1] += error * 3 / 16;
pixels_dst[y + 1][x] += error * 5 / 16;
pixels_dst[y][x + 1] += error * 1 / 16;
pixels_dst[y + 1][x - 1] += error * 1 / 16;
pixels_dst[y + 1][x] += error * 1 / 16;
pixels_dst[y + 1][x + 1] += error * 1 / 16;
}
image.release();

View File

@ -1,75 +1,13 @@
//#ifndef IMAGE_APPLY_BW_BINARAY_H
//#define IMAGE_APPLY_BW_BINARAY_H
//
//#include "ImageApply.h"
//
//class CImageApplyBWBinaray:public CImageApply
//{
//public:
//
// enum class ThresholdType
// {
// THRESH_BINARY = 0,
// THRESH_OTSU,
//
// ADAPTIVE_GAUSSIAN,
// ADAPTIVE_MEAN,
//
// ERROR_DIFFUSION
// };
//
// CImageApplyBWBinaray(ThresholdType type, int threshold = 180, int blockSize = 25, int constant = 5);
//
// CImageApplyBWBinaray();
//
// virtual ~CImageApplyBWBinaray(void);
//
// virtual void apply(cv::Mat& pDib,int side);
//
// virtual void apply(std::vector<cv::Mat>& mats, bool isTwoSide);
//
// double getThreshold() { return m_threshold; }
//
// ThresholdType getThresholdType() { return m_type; }
//
// int getBlockSize() { return m_blockSize; }
//
// double getConstant() { return m_constant; }
//
// void setThreshold(double value) { m_threshold = value; }
//
// void setThresholdType(ThresholdType type) { m_type = type; }
//
// void setBlockSize(int value) { m_blockSize = value; }
//
// void setConstant(double value) { m_constant = value; }
//
//private:
//
// void errorDiffuse(cv::Mat& image);
//
//private:
// double m_threshold;
//
// ThresholdType m_type;
//
// int m_blockSize;
//
// double m_constant;
//
// uchar* m_table;
//};
//
//#endif //!IMAGE_APPLY_BW_BINARAY_H
//
/*
* ====================================================
*
*
* 2020/4/21
* 2020/4/21
* v1.0
*
*
* 2020/4/21
* 2020/5/28 v1.1
2020/5/29 v1.2
2020/6/19 v1.3
* v1.3
* ====================================================
*/
@ -79,34 +17,34 @@
#include "ImageApply.h"
class CImageApplyBWBinaray :public CImageApply
class CImageApplyBWBinaray:public CImageApply
{
public:
enum class ThresholdType
{
THRESH_BINARY = 0, //传统二值化
THRESH_OTSU, //大津阈值
THRESH_BINARY = 0, //传统二值化
THRESH_OTSU, //大津阈值
ADAPTIVE_GAUSSIAN, //高斯局部自适应阈值
ADAPTIVE_MEAN, //均值局部自适应阈值
ADAPTIVE_GAUSSIAN, //高斯局部自适应阈值
ADAPTIVE_MEAN, //均值局部自适应阈值
ERROR_DIFFUSION //错误扩散
ERROR_DIFFUSION //错误扩散
};
/*
* type [in]:
* threshold [in]:THRESH_OTSU时无效
* blockSize [in]:ADAPTIVE_GAUSSIAN和ADAPTIVE_MEAN模式有效
* constant [in]:ADAPTIVE_GAUSSIAN和ADAPTIVE_MEAN模式有效blockSize形成比例关系
*/
/*
* type [in]:
* threshold [in]:THRESH_OTSU时无效
* blockSize [in]:ADAPTIVE_GAUSSIAN和ADAPTIVE_MEAN模式有效
* constant [in]:ADAPTIVE_GAUSSIAN和ADAPTIVE_MEAN模式有效blockSize形成比例关系
*/
CImageApplyBWBinaray(ThresholdType type, int threshold = 120, int blockSize = 25, int constant = 5);
CImageApplyBWBinaray();
virtual ~CImageApplyBWBinaray(void);
virtual void apply(cv::Mat& pDib, int side);
virtual void apply(cv::Mat& pDib,int side);
virtual void apply(std::vector<cv::Mat>& mats, bool isTwoSide);

View File

@ -0,0 +1,42 @@
#include "ImageApplyDetachNoise.h"
#include "ImageProcess_Public.h"
CImageApplyDetachNoise::CImageApplyDetachNoise(int noise)
: m_noise(noise)
{
}
CImageApplyDetachNoise::~CImageApplyDetachNoise(void)
{
}
void CImageApplyDetachNoise::apply(cv::Mat& pDib, int side)
{
(void)side;
if (pDib.empty()||pDib.channels() != 1)
return;
cv::Mat mask;
cv::threshold(pDib, mask, 127, 255, cv::THRESH_BINARY_INV);
std::vector<std::vector<cv::Point>> contours;
std::vector<cv::Vec4i> h;
hg::findContours(mask, contours, h);
for (const std::vector<cv::Point>& contour : contours)
if (contourArea(contour) < m_noise)
fillConvexPoly(pDib, contour, cv::Scalar(255));
}
void CImageApplyDetachNoise::apply(std::vector<cv::Mat> &mats, bool isTwoSide)
{
(void)isTwoSide;
int i = 0;
for (cv::Mat& var : mats) {
if (i != 0 && isTwoSide == false)
break;
if (!var.empty())
apply(var, 0);
i++;
}
}

View File

@ -0,0 +1,38 @@
/*
* ====================================================
* 3*3
*
* 2020/4/21
* 2020/4/21 v1.0
2020/5/29 v1.1 使
* v1.1
* ====================================================
*/
#ifndef IMAGE_APPLY_DETACH_NOISE_H
#define IMAGE_APPLY_DETACH_NOISE_H
#include "ImageApply.h"
class CImageApplyDetachNoise : public CImageApply
{
public:
CImageApplyDetachNoise(int noise = 4);
inline int getNoise() { return m_noise; }
inline void setNoise(int noise) { m_noise = noise; }
virtual ~CImageApplyDetachNoise(void);
virtual void apply(cv::Mat& pDib, int side);
virtual void apply(std::vector<cv::Mat>& mats, bool isTwoSide);
private:
int m_noise;
};
#endif // !IMAGE_APPLY_DETACH_NOISE_H

View File

@ -0,0 +1,144 @@
#include "ImageApplyHSVCorrect.h"
#include <omp.h>
CImageApplyHSVCorrect::CImageApplyHSVCorrect()
: m_table(new uint[256 * 256 * 256])
{
initLUT();
}
CImageApplyHSVCorrect::CImageApplyHSVCorrect(CorrectOption mode)
: m_table(new uint[256 * 256 * 256])
{
initLUT();
switch (mode)
{
case CImageApplyHSVCorrect::Red_Removal:
set_HSV_value(std::pair<uchar, uchar>(0, 63), std::pair<uchar, uchar>(20, 255), std::pair<uchar, uchar>(160, 255), 0x00FFFFFF);
set_HSV_value(std::pair<uchar, uchar>(191, 255), std::pair<uchar, uchar>(20, 255), std::pair<uchar, uchar>(160, 255), 0x00FFFFFF);
break;
default:
break;
}
}
CImageApplyHSVCorrect::~CImageApplyHSVCorrect()
{
delete [] m_table;
}
void CImageApplyHSVCorrect::apply(cv::Mat &pDib, int side)
{
(void)side;
if (pDib.empty() || pDib.channels() != 3) return;
uchar* src = pDib.data;
cv::Mat z = cv::Mat::zeros(pDib.size(), CV_8UC3);
uchar* dst = z.data;
int total = pDib.total();
#pragma omp parallel for
for (int i = 0; i < total; i++)
{
int offset = i * 3;
int index = *reinterpret_cast<uint*>(src + offset) & 0x00ffffff;
uint color = m_table[index];
*reinterpret_cast<uint*>(dst + offset) |= color;
}
pDib = z;
}
void CImageApplyHSVCorrect::apply(std::vector<cv::Mat> &mats, bool isTwoSide)
{
(void)isTwoSide;
int i = 0;
for (cv::Mat& var : mats) {
if (i != 0 && isTwoSide == false)
break;
if (!var.empty())
apply(var, 0);
i++;
}
}
void CImageApplyHSVCorrect::initLUT()
{
#if 0
uchar h, s, v;
#endif
for (uint b = 0; b < 256; b++)
for (uint g = 0; g < 256; g++)
for (uint r = 0; r < 256; r++)
{
#if 0
RGB_2_HSV_full(r, g, b, h, s, v);
uint index = b | (g << 8) | (r << 16);
if (h < 12 || h > 245)
m_table[index] = index & 0x00ffffff;
else
m_table[index] = (v | (v << 8) | (v << 16)) & 0x00ffffff;
#else
m_table[b | (g << 8) | (r << 16)] = b | (g << 8) | (r << 16);
#endif
}
}
void CImageApplyHSVCorrect::set_single(const uint src_b, const uint src_g, const uint src_r,
const uint dst_b, const uint dst_g, const uint dst_r)
{
m_table[src_b | (src_g << 8) | (src_r << 16)] = dst_b | (dst_g << 8) | (dst_r << 16);
}
void CImageApplyHSVCorrect::set_HSV_value(const std::pair<uchar, uchar>& range_h,
const std::pair<uchar, uchar>& range_s,
const std::pair<uchar, uchar>& range_v,
uint bgr)
{
uchar h, s, v;
for (int b = 0; b < 256; b++)
for (int g = 0; g < 256; g++)
for (int r = 0; r < 256; r++)
{
RGB_2_HSV_full(r, g, b, h, s, v);
if (contained(h, range_h) && contained(s, range_s) && contained(v, range_v))
m_table[(b | (g << 8) | (r << 16)) & 0x00ffffff] = bgr & 0x00ffffff;
}
}
void CImageApplyHSVCorrect::set_table(const uint* table)
{
memcpy(m_table, table, 256 * 256 * 256);
}
bool CImageApplyHSVCorrect::contained(uchar value, const std::pair<uchar, uchar> &range)
{
return value >= range.first && value <= range.second;
}
void CImageApplyHSVCorrect::RGB_2_HSV_full(int r, int g, int b, uchar& h, uchar& s, uchar& v)
{
int minn = cv::min(r, cv::min(g, b));
int maxx = cv::max(r, cv::max(g, b));
v = static_cast<uchar>(maxx); //V
int delta = maxx - minn;
float _h;
if (maxx == 0)
{
h = s = v = 0;
return;
}
else
s = static_cast<uchar>(delta * 255 / maxx);
if (r == maxx)
_h = static_cast<float>(g - b) / static_cast<float>(delta);
else if (g == maxx)
_h = 2 + static_cast<float>(b - r) / static_cast<float>(delta);
else
_h = 4 + static_cast<float>(r - g) / static_cast<float>(delta);
float __h = _h * 42.6666666667f;
h = (__h >= 0) ? static_cast<uchar>(__h) : static_cast<uchar>(__h + 256);
}

View File

@ -0,0 +1,87 @@
/*
* ====================================================
* LUT实现BGR查值表HVSBGR原图进行查值校正
*
* 2020/3/21
* v1.0 2020/3/21
v1.1 2020/6/15 HSV取值范围
* v1.1
* ====================================================
*/
#ifndef IMAGE_APPLY_COLOR_CORRECT_H
#define IMAGE_APPLY_COLOR_CORRECT_H
#include "ImageApply.h"
class CImageApplyHSVCorrect : public CImageApply
{
public:
enum CorrectOption
{
Red_Removal //除掉红色。红色定义H:[0, 85][170, 255],S:[10, 255],V:[120,255]
};
public:
CImageApplyHSVCorrect();
/*
* mode [in]:
*/
CImageApplyHSVCorrect(CorrectOption mode);
virtual ~CImageApplyHSVCorrect();
virtual void apply(cv::Mat& pDib,int side);
virtual void apply(std::vector<cv::Mat>& mats, bool isTwoSide);
/*
* RGBR在高位B在低位32
[00x00FFFFFF]
*/
void initLUT();
/*
* RGB索引值设置为目标值
= src_b | (src_g << 8) | (src_r << 16)
= dst_b | (dst_g << 8) | (dst_r << 16)
* src_b:[in] B通道索引
* src_g:[in] G通道索引
* src_r:[in] R通道索引
* dst_b:[in] B通道值
* dst_g:[in] G通道值
* dst_r:[in] R通道值
*/
void set_single(const uint src_b, const uint src_g, const uint src_r,
const uint dst_b, const uint dst_g, const uint dst_r);
/*
* HSV色彩空间描述色彩范围BGR索引设置为0x00FFFFFF(
* range_h:[in] H分量范围[0, 255]
* range_s:[in] S分量范围[0, 255]
* range_v:[in] V分量范围[0, 255]
* bgr:[in] uint表示BGR值B在低位R在高位
*/
void set_HSV_value(const std::pair<uchar, uchar>& range_h,
const std::pair<uchar, uchar>& range_s,
const std::pair<uchar, uchar>& range_v,
uint bgr = 0x00FFFFFF);
/*
* 256 * 256 * 256 * sizeof(uint
* table:[in]
*/
void set_table(const uint* table);
private:
static bool contained(uchar value, const std::pair<uchar, uchar>& range);
static void RGB_2_HSV_full(int r, int g, int b, uchar& h, uchar& s, uchar& v);
private:
uint* m_table;
};
#endif

View File

@ -13,5 +13,6 @@
#include "ImageApplyRotation.h"
#include "ImageApplySharpen.h"
#include "ImageApplyConcatenation.h"
#include "ImageApplyHSVCorrect.h"
#endif