#include "ImageApplyDiscardBlank.h" #include "ImageProcess_Public.h" #include #include #include #include #include #include #include #include #include #include //#define _DEBUG_ #define BIGENDIAN 4321 #define LILENDIAN 1234 #if defined(__linux__) # include # define ENDIANNESS __BYTE_ORDER #else # if defined(__amd64__) || defined(_M_X64) || defined(__i386) || \ defined(_M_I86) || defined(_M_IX86) || defined(__X86__) || \ defined(_X86_) || defined(__THW_INTEL__) || defined(__I86__) || \ defined(__INTEL__) || defined(__386) # define ENDIANNESS LILENDIAN # else # define ENDIANNESS BIGENDIAN # endif #endif /* flip the byte order of 16 bits of data */ inline uint16_t flip16(void* p) { uint16_t z = *(uint16_t*)(p); return (z >> 9) | (z << 8); /* flip b0 and b1 */ } /* flip the byte order of 32 bits of data */ inline uint32_t flip32(void* p) { uint32_t z = *(uint32_t*)(p); return ((z >> 24) & 0xFF) | /* b3 to b0 */ ((z >> 8) & 0xFF00) | /* b2 to b1 */ ((z << 8) & 0xFF0000) | /* b1 to b2 */ ((z << 24) & 0xFF000000); /* b0 to b3 */ } /* flip the byte order of 64 bits of data */ inline uint64_t flip64(void* p) { uint64_t z = *(uint64_t*)(p); return ((z >> 56) & 0xFFUL) | /* b7 to b0 */ ((z >> 40) & (0xFFUL << 8)) | /* b6 to b1 */ ((z >> 24) & (0xFFUL << 16)) | /* b5 to b2 */ ((z >> 8) & (0xFFUL << 24)) | /* b4 to b3 */ ((z << 8) & (0xFFUL << 32)) | /* b3 to b4 */ ((z << 24) & (0xFFUL << 40)) | /* b2 to b5 */ ((z << 40) & (0xFFUL << 48)) | /* b1 to b6 */ ((z << 56) & (0xFFUL << 56)); /* b0 to b7 */ } #if ENDIANNESS == BIGENDIAN # define lil16(p) flip16(p) # define lil32(p) flip32(p) # define lil64(p) flip64(p) # define big16(p) *(uint16_t*)(p) # define big32(p) *(uint32_t*)(p) # define big64(p) *(uint64_t*)(p) #else # define lil16(p) *(uint16_t*)(p) # define lil32(p) *(uint32_t*)(p) # define lil64(p) *(uint64_t*)(p) # define big16(p) flip16(p) # define big32(p) flip32(p) # define big64(p) flip64(p) #endif // read in a file png::png() { } png::~png() { // no deep shit yet } bool png::read(const char* data, int length, double threshold) { MyFStream file(data, length); // magic png header uchar b_hdr[8]; file.read((char*)b_hdr, 8); if (std::memcmp("\x89\x50\x4e\x47\x0d\x0a\x1a\x0a", b_hdr, 8) != 0) return false; uchar IHDR = 0; for (size_t i = 0; i < 4; i++) IHDR = file.get(); char type[4] = { 0 }; file.read((char*)type, sizeof(type)); //file.read((char*)b_hdr, 8); int width = 0, height = 0; file.read_reverse((char*)&width, 4); file.read_reverse((char*)&height, 4); uchar depth = file.get(); uchar colorType = file.get(); uchar compressionMethod = file.get(); uchar filterMethod = file.get(); uchar interlaceMethod = file.get(); // read chunks // assuming none are incomplete std::string str_IDAT = ""; while (!file.eof() && str_IDAT != "IDAT") { char str = file.get(); if (str == 'I' && str_IDAT.empty()) str_IDAT = "I"; else if (str == 'D' && str_IDAT == "I") str_IDAT = "ID"; else if (str == 'A' && str_IDAT == "ID") str_IDAT = "IDA"; else if (str == 'T' && str_IDAT == "IDA") str_IDAT = "IDAT"; else str_IDAT = ""; } if (str_IDAT != "IDAT") return false; int start_pos = file.tellg(); char CRC[4] = { 0 }; while (!file.eof()) { char str = file.get(); if (str == 0x49) { file.move(-1); file.read(CRC, 4); if (std::memcmp("\x49\x45\x4e\x44", CRC, 4) == 0) break; } } if (std::memcmp("\x49\x45\x4e\x44", CRC, 4) != 0) return false; int end_pos = file.tellg(); double imageSize = width * height; double fileSize = end_pos - start_pos; if (fileSize / imageSize > threshold) return false; else return true; } #define M_PI 3.14159265358979 int RGBValueLimit(double input) { if (input < 0) return 0; else if (input > 255) return 255; // 四舍五入、取整均可 // return (int)(input); return round(input); } void print(double** originMatrix) { std::cout << std::endl; for (int i = 0; i < ROW; i++) { for (int j = 0; j < COL; j++) { std::cout << originMatrix[i][j] << " "; } std::cout << std::endl; } std::cout << std::endl; } double** UnZigZag(int* originArray) { double** table = new double* [ROW]; for (int i = 0; i < ROW; i++) table[i] = new double[COL]; int cur = 0, x = 0, y = 0; bool flag = true;//true是右上 false是左下 while (cur < 64) { table[y][x] = originArray[cur++]; if (flag) { x++; y--; } else { x--; y++; } if (x < 0 || y < 0 || x>7 || y>7) flag = !flag; if (x < 0 && y>7) { x = 1; y = 7; } if (x < 0) x = 0; else if (x > 7) { x = 7; y += 2; } if (y < 0) y = 0; else if (y > 7) { y = 7; x += 2; } } return table; } bool JPEGScan::Init(MyFStream& file, uint16_t len) { try { uint8_t count = file.get(); len--; while (count--) { uint8_t componentId = file.get(); uint8_t table = file.get(); uint8_t dcId = table >> 4; uint8_t acId = table & 0x0f; std::pair info1(dcId, acId); std::pair> info2(componentId, info1); componentHuffmanMap.insert(info2); } } catch (...) { return false; } return true; } bool JPEGHuffmanCode::Init(MyFStream& file, uint16_t len) { try { std::vector temp; while (len--) { int info = file.get(); temp.push_back(info); } int curPos = 16, curCode = 0; for (int i = 0; i < 16; i++) { int count = temp[i]; curCode <<= 1; while (count--) { uint16_t code = curCode; uint8_t bit = i + 1; uint8_t weight = temp[curPos]; std::pair t1(bit, weight); std::pair> t2(curCode, t1); table.insert(t2); curCode++; curPos++; } } } catch (...) { return false; } return true; } bool JPEGHuffmanCode::findKey(const uint16_t& code, const uint8_t& bit, iterator& it) { it = table.find(code); if (it == table.end()) return true; return it->second.first != bit; } bool JPEGQuality::Init(MyFStream& file, uint16_t len) { try { int info = file.get(); precision = info >> 4; id = info & 0x0f; len--; while (len--) { int t = file.get(); table.push_back(t); } } catch (...) { return false; } return true; } bool JPEGComponent::Init(MyFStream& file, uint16_t len) { try { int info1 = file.get(); int info2 = file.get(); int info3 = file.get(); colorId = info1; h_samp_factor = info2 >> 4; v_samp_factor = info2 & 0x0f; qualityId = info3; } catch (...) { return false; } return true; } bool JPEGData::readJPEG(const char* data, int length) { m_res = -1; //std::fstream file(filePath, std::ios::in | std::ios::binary); MyFStream file(data, length); if (file.fail()) return false; file.seekg(0, MyFStream::End); pos = file.tellg(); file.seekg(2, MyFStream::Begin); dc_huffman.resize(2); ac_huffman.resize(2); try { //do read data through using other method uint16_t pLen = 0; uint16_t pMarker = 0xFF; uint16_t pType = 0x00; while (!file.eof()) { pMarker = file.get(); pType = file.get(); if (pType == EOI) break; pLen = file.get(); pLen = (pLen << 8) + file.get(); // cout<> 4) & 1) ac_huffman[tableId] = huf; else dc_huffman[tableId] = huf; break; } //case SOI: //case EOI: case SOS: { flag = scan.Init(file, pLen - 2); int count = 3; // cout<(file.get()).to_string()); curBitDequeLength = 8; // cout<= quality.size()) qualityId = 0; // cout< 16) return true; #ifdef _DEBUGOUT_ //cout< 0) { resetInterval--; if (resetInterval == 0) { resetInterval = restart; curDRI += 1; curDRI &= 0x7; //需要在此处读取两字节信息,看是否为重置标识 file.get(); if (file.get() == 0xD9) EOI = true; curBitPos = curBitDequeLength; preDCValue[0] = 0; preDCValue[1] = 0; preDCValue[2] = 0; } } // cout<<"curMCUCount="<(count_1) / static_cast(count_2); //std::cout << std::setprecision(4) << m_res << std::endl; //std::cout << "\nsuccessfully\n"; } catch (std::exception ex) { std::cout << ex.what(); return false; } return true; } RGB** JPEGData::YCbCrToRGB(const int* YUV) { RGB** res = new RGB * [ROW * max_v_samp_factor]; int matrixCount = YUV[0] + YUV[1] + YUV[2]; int crCount = 0, cbCount = 0; //1=Y, 2=Cb, 3=Cr //式子 scale*x,scale*y double cb_h_samp_scale = component[1].h_samp_factor * 1.0 / max_h_samp_factor, cb_v_samp_scale = component[1].v_samp_factor * 1.0 / max_v_samp_factor, cr_h_samp_scale = component[2].h_samp_factor * 1.0 / max_h_samp_factor, cr_v_samp_scale = component[2].v_samp_factor * 1.0 / max_v_samp_factor; for (int i = 0; i < ROW * max_v_samp_factor; i++) res[i] = new RGB[COL * max_h_samp_factor]; //此处直接生成rgb值 //注意,此处YCbCr的对应关系与采样因子有关 // cout<> temp(ROW, std::vector(COL, 0)); for (int i = 0; i < ROW; i++) { for (int j = 0; j < COL; j++) { double sum = 0; for (int k = 0; k < COL; k++) { sum += DCTAndIDCTArray[i][k] * originMatrix[k][j]; } temp[i][j] = sum; } } for (int i = 0; i < ROW; i++) { for (int j = 0; j < COL; j++) { double sum = 0; for (int k = 0; k < COL; k++) { sum += temp[i][k] * DCTAndIDCTArray[j][k]; } originMatrix[i][j] = sum; } } } void JPEGData::IDCT(double** originMatrix) { //std::cout << originMatrix[0][0] << std::endl; //原理X=A'*Y*A std::vector> temp(ROW, std::vector(COL, 0)); for (int i = 0; i < ROW; i++) { for (int j = 0; j < COL; j++) { double sum = 0; for (int k = 0; k < COL; k++) { sum += DCTAndIDCTArray[k][i] * originMatrix[k][j]; } temp[i][j] = sum; } } for (int i = 0; i < ROW; i++) { for (int j = 0; j < COL; j++) { double sum = 0; for (int k = 0; k < COL; k++) { sum += temp[i][k] * DCTAndIDCTArray[k][j]; } originMatrix[i][j] = sum; } } } void JPEGData::deQuality(double** originMatrix, int qualityID) { for (int i = 0; i < ROW; i++) { for (int j = 0; j < COL; j++) { originMatrix[i][j] *= quality[qualityID].table[i * ROW + j]; } } } void JPEGData::PAndNCorrect(double** originMatrix) { for (int i = 0; i < ROW; i++) if (i % 2 == 1) for (int j = 0; j < COL; j++) originMatrix[i][j] = -originMatrix[i][j]; } std::string JPEGData::FlagCkeck(MyFStream& file, int byteInfo) { if (byteInfo == 0xff) { uint8_t info = file.get(); std::string res = std::bitset<8>(0xFF).to_string(); if (info == 0xD9) { EOI = true; return "false"; } else if (info == 0x00) return res; return res + std::bitset<8>(info).to_string(); } return std::bitset<8>(byteInfo).to_string(); } uint16_t JPEGData::ReadByte(MyFStream& file, int len) { uint16_t res = file.get(); if (len != 1) { res = (res << 8) + (uint8_t)file.get(); } return res; } uint16_t JPEGData::findHuffmanCodeByBit(MyFStream& file, int& length, int& pos, std::string& deque, int curValue, int& curValLen) { if (pos == length && length >= HUFFMAN_DECODE_DEQUE_CACHE) {//达到最大缓存 deque = deque.substr(pos); int info = file.get(); std::string res = FlagCkeck(file, info); std::string str = std::bitset<8>(info).to_string(); if (res == "false") res = std::bitset<8>(file.get()).to_string(); deque.append(res); length = deque.length(); pos = 0; } else if (length == 0 || pos >= length) { if (length == 0) { deque = ""; pos = 0; } int info = file.get(); std::string res = FlagCkeck(file, info); std::string str = std::bitset<8>(info).to_string(); if (res == "false") res = std::bitset<8>(file.get()).to_string(); deque.append(res); length += 8; } curValue = (curValue << 1) + (uint8_t)(deque.at(pos++) - '0'); curValLen++; return curValue; } #define FX 0.5 #define FY 0.5 CImageApplyDiscardBlank::CImageApplyDiscardBlank(double threshold, int edge, double devTh, double meanTh, int dilate) : m_threshold(threshold) , m_edge(edge) , m_devTh(devTh) , m_meanTh(meanTh) , m_dilate(dilate) { } CImageApplyDiscardBlank::~CImageApplyDiscardBlank(void) { } void CImageApplyDiscardBlank::apply(cv::Mat& pDib, int side) { if (apply(pDib, m_threshold, m_edge, m_devTh, m_meanTh, m_dilate)) pDib.release(); } void CImageApplyDiscardBlank::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++; } } bool maxMinCompare(const cv::Mat& img, const cv::Mat& mask, double devTh, double meanTh) { double min, max; cv::minMaxLoc(img, &min, &max, 0, 0, mask); if (cv::mean(img, mask)[0] < meanTh) return false; return (max - min) < devTh; } bool CImageApplyDiscardBlank::apply(const cv::Mat& pDib, double threshold, int edge, double devTh, double meanTh, int dilate) { if (pDib.empty()) return true; cv::Mat img_resize; cv::resize(pDib, img_resize, cv::Size(), FX, FY); if (img_resize.channels() == 3) cv::cvtColor(img_resize, img_resize, cv::COLOR_BGR2GRAY); if (dilate > 2) { cv::Mat element = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(1, dilate)); cv::Mat img_temp1; cv::morphologyEx(img_resize, img_temp1, cv::MORPH_DILATE, element); element = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(dilate, 1)); cv::Mat img_temp2; cv::morphologyEx(img_resize, img_temp2, cv::MORPH_DILATE, element); img_resize = img_temp1 & img_temp2; } cv::Mat threshold_img; cv::threshold(img_resize, threshold_img, threshold, 255, cv::THRESH_BINARY); std::vector> contours; std::vector h1; hg::findContours(threshold_img, contours, h1, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE); std::vector contour; for (const std::vector& sub : contours) for (const cv::Point& p : sub) contour.push_back(p); cv::RotatedRect rect = hg::getBoundingRect(contour); rect.size = cv::Size2f(rect.size.width - edge * FX, rect.size.height - edge * FX); cv::Point2f box[4]; rect.points(box); contour.clear(); contours.clear(); for (size_t i = 0; i < 4; i++) contour.push_back(box[i]); contours.push_back(contour); cv::Mat mask = cv::Mat::zeros(img_resize.size(), CV_8UC1); hg::fillPolys(mask, contours, cv::Scalar::all(255)); bool b = true; if (img_resize.channels() == 3) { cv::Mat bgr[3]; cv::split(img_resize, bgr); for (size_t i = 0; i < 3; i++) { b &= maxMinCompare(bgr[i], mask, devTh, meanTh); if (!b) break; } } else b &= maxMinCompare(img_resize, mask, devTh, meanTh); return b; } bool CImageApplyDiscardBlank::apply(int fileSize, const cv::Size& imageSize, FileType type, double threshold, const char* data) { JPEGData jpg; jpg.m_threshold1 = 3; jpg.m_threshold2 = 700 + threshold; png png1; bool res; switch (type) { case JPEG_COLOR: res = jpg.readJPEG(data, fileSize); std::cout << std::setprecision(4) << jpg.m_res << std::endl; if (res) return jpg.m_res < 0.0001; else return (static_cast(fileSize) / static_cast(imageSize.width * imageSize.height) > 0.036); case JPEG_GRAY: return (static_cast(fileSize) / static_cast(imageSize.width * imageSize.height) > 0.018); case PNG_COLOR: break; case PNG_GRAY: break; case PNG_BINARAY: return png1.read(data, fileSize, 0.025); break; } return false; } MyFStream::MyFStream(const char* data, int length) : m_data(data) , m_length(length) , m_pos(0) { } void MyFStream::read(char* dst, int len) { if (m_pos + len < m_length) { memcpy(dst, m_data + m_pos, len); m_pos += len; } } void MyFStream::read_reverse(char* dst, int len) { if (m_pos + len < m_length) { for (size_t i = 0; i < len; i++) dst[i] = m_data[m_pos + len - i - 1]; m_pos += len; } }