//#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" 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) , 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(160) , 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) { (void)side; if (pDib.empty()) return; if (pDib.channels() == 3) cv::cvtColor(pDib, pDib, cv::COLOR_BGR2GRAY); switch (m_type) { case ThresholdType::THRESH_BINARY: { //ImageInfo info; //info.data = pDib.data; //info.width = pDib.step; //info.height = pDib.rows; //adaptivethresh(info, 80, 255, 127); cv::threshold(pDib, pDib, m_threshold, 255, CV_THRESH_BINARY); //cv::adaptiveThreshold(pDib, pDib, 255, cv::ADAPTIVE_THRESH_GAUSSIAN_C, CV_THRESH_BINARY, 91, 21); //cv::Mat integ; //cv::integral(pDib, integ, CV_32S); //int blockSize = 30;//邻域尺寸 //int threshold = 4; //int low = 115; //int up = 200; //int halfSize = blockSize / 2; //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]) / (blockSize * blockSize); // 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; // } // } //} 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) { (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) { 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; }