diff --git a/huagao/ImageProcess/ImageApplyBWBinaray.cpp b/huagao/ImageProcess/ImageApplyBWBinaray.cpp index 14d868b9..39cdfdbc 100644 --- a/huagao/ImageProcess/ImageApplyBWBinaray.cpp +++ b/huagao/ImageProcess/ImageApplyBWBinaray.cpp @@ -1,4 +1,366 @@ +//#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(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(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& 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(image.rows) - 1; +// size_t cols = static_cast(image.cols) - 1; +// +// short** pixels_dst = new short*[static_cast(image.rows)]; +// for (int i = 0; i < image.rows; i++) +// pixels_dst[i] = reinterpret_cast(dst.data + i * static_cast(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; +} + CImageApplyBWBinaray::CImageApplyBWBinaray(ThresholdType type, int threshold, int blockSize, int constant) : m_threshold(threshold) @@ -12,7 +374,7 @@ CImageApplyBWBinaray::CImageApplyBWBinaray(ThresholdType type, int threshold, in } CImageApplyBWBinaray::CImageApplyBWBinaray() - : m_threshold(180) + : m_threshold(160) , m_type(ThresholdType::THRESH_BINARY) , m_blockSize(25) , m_constant(5) @@ -28,18 +390,10 @@ CImageApplyBWBinaray::~CImageApplyBWBinaray(void) delete[] m_table; } -void CImageApplyBWBinaray::apply(cv::Mat& pDib,int side) +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; - } + (void)side; + if (pDib.empty()) return; if (pDib.channels() == 3) cv::cvtColor(pDib, pDib, cv::COLOR_BGR2GRAY); @@ -47,8 +401,75 @@ void CImageApplyBWBinaray::apply(cv::Mat& pDib,int side) switch (m_type) { case ThresholdType::THRESH_BINARY: - cv::threshold(pDib, pDib, m_threshold, 255, CV_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> contours; + //std::vector h; + //hg::findContours(mask, contours, h); + //mask.release(); + + //for (const std::vector& 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(j); + int* idata1 = integ.ptr(j - halfSize); + int* idata2 = integ.ptr(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; + } + } + } + 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> contours; + std::vector h; + hg::findContours(mask, contours, h); + mask.release(); + + for (const std::vector& 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); break; + } case ThresholdType::THRESH_OTSU: cv::threshold(pDib, pDib, m_threshold, 255, CV_THRESH_OTSU); break; @@ -72,20 +493,18 @@ void CImageApplyBWBinaray::apply(cv::Mat& pDib,int side) void CImageApplyBWBinaray::apply(std::vector& 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)isTwoSide; + int i = 0; + for (cv::Mat& var : mats) { + if (i != 0 && isTwoSide == false) + break; + if (!var.empty()) + apply(var, 0); + i++; } } -void CImageApplyBWBinaray::errorDiffuse(cv::Mat & image) +void CImageApplyBWBinaray::errorDiffuse(cv::Mat& image) { if (image.rows < 3 || image.cols < 3) { @@ -99,7 +518,7 @@ void CImageApplyBWBinaray::errorDiffuse(cv::Mat & image) size_t rows = static_cast(image.rows) - 1; size_t cols = static_cast(image.cols) - 1; - short** pixels_dst = new short*[static_cast(image.rows)]; + short** pixels_dst = new short* [static_cast(image.rows)]; for (int i = 0; i < image.rows; i++) pixels_dst[i] = reinterpret_cast(dst.data + i * static_cast(dst.step)); diff --git a/huagao/ImageProcess/ImageApplyBWBinaray.h b/huagao/ImageProcess/ImageApplyBWBinaray.h index 9f062f97..9be206b7 100644 --- a/huagao/ImageProcess/ImageApplyBWBinaray.h +++ b/huagao/ImageProcess/ImageApplyBWBinaray.h @@ -1,30 +1,112 @@ +//#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& 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 + + * ==================================================== + */ + #ifndef IMAGE_APPLY_BW_BINARAY_H #define IMAGE_APPLY_BW_BINARAY_H #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 //错误扩散 }; - CImageApplyBWBinaray(ThresholdType type, int threshold = 180, int blockSize = 25, int constant = 5); + /* + * 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& mats, bool isTwoSide); diff --git a/huagao/ImageProcess/ImageApplyChannel.cpp b/huagao/ImageProcess/ImageApplyChannel.cpp index 4e1832b4..d4e7c6bb 100644 --- a/huagao/ImageProcess/ImageApplyChannel.cpp +++ b/huagao/ImageProcess/ImageApplyChannel.cpp @@ -1,17 +1,21 @@ #include "ImageApplyChannel.h" - +//#include "ImageApplyAdjustColors.h" CImageApplyChannel::CImageApplyChannel() : m_channel(Invalid) + //, colors(new CImageApplyAdjustColors(0, 30, 1.0)) { } CImageApplyChannel::CImageApplyChannel(Channel channel) : m_channel(channel) + //,colors(new CImageApplyAdjustColors(0, 30, 1.0)) { } CImageApplyChannel::~CImageApplyChannel(void) { + //if (colors != NULL) + //delete colors; } void CImageApplyChannel::apply(cv::Mat& pDib,int side) @@ -33,6 +37,7 @@ void CImageApplyChannel::apply(cv::Mat& pDib,int side) { case Red: cv::extractChannel(pDib, dst, 2); + //colors->apply(pDib, side); break; case Green: cv::extractChannel(pDib, dst, 1); diff --git a/huagao/ImageProcess/ImageApplyChannel.h b/huagao/ImageProcess/ImageApplyChannel.h index cb7d9017..c703eade 100644 --- a/huagao/ImageProcess/ImageApplyChannel.h +++ b/huagao/ImageProcess/ImageApplyChannel.h @@ -2,7 +2,7 @@ #define IMAGE_APPLY_CHANNEL_H #include "imageapply.h" - +//class CImageApplyAdjustColors; class CImageApplyChannel : public CImageApply { public: @@ -37,6 +37,7 @@ private: private: Channel m_channel; + //CImageApplyAdjustColors* colors; }; #endif // !IMAGE_APPLY_CHANNEL_H \ No newline at end of file