template<class T, int D> inline T vecDist( const cv::Vec<T, D> &v1, const cv::Vec<T, D> &v2 ) { return sqrt( vecSqrDist( v1, v2 ) ); } // out of range risk for T = byte, ...
int CmColorQua::D_Quantize(CMat& img3f, Mat &idx1i, Mat &_color3f, Mat &_colorNum, double ratio, const int clrNums[3]) { float clrTmp[3] = {clrNums[0] - 0.0001f, clrNums[1] - 0.0001f, clrNums[2] - 0.0001f}; int w[3] = {clrNums[1] * clrNums[2], clrNums[2], 1}; CV_Assert(img3f.data != NULL); idx1i = Mat::zeros(img3f.size(), CV_32S); int rows = img3f.rows, cols = img3f.cols; if (img3f.isContinuous() && idx1i.isContinuous()){ cols *= rows; rows = 1; } // Build color pallet for (int y = 0; y < rows; y++) { const float* imgDataP = img3f.ptr<float>(y); int* idx = idx1i.ptr<int>(y); #pragma omp parallel for for (int x = 0; x < cols; x++){ const float* imgData = imgDataP + 3*x; idx[x] = (int)(imgData[0]*clrTmp[0])*w[0] + (int)(imgData[1]*clrTmp[1])*w[1] + (int)(imgData[2]*clrTmp[2]); } } map<int, int> pallet; for (int y = 0; y < rows; y++) { int* idx = idx1i.ptr<int>(y); for (int x = 0; x < cols; x++) pallet[idx[x]] ++; } // Find significant colors int maxNum = 0; { int count = 0; vector<pair<int, int>> num; // (num, color) pairs in num num.reserve(pallet.size()); for (map<int, int>::iterator it = pallet.begin(); it != pallet.end(); it++) num.push_back(pair<int, int>(it->second, it->first)); // (color, num) pairs in pallet sort(num.begin(), num.end(), std::greater<pair<int, int>>()); maxNum = (int)num.size(); int maxDropNum = cvRound(rows * cols * (1-ratio)); for (int crnt = num[maxNum-1].first; crnt < maxDropNum && maxNum > 1; maxNum--) crnt += num[maxNum - 2].first; maxNum = min(maxNum, 256); // To avoid very rarely case if (maxNum <= 10) maxNum = min(10, (int)num.size()); pallet.clear(); for (int i = 0; i < maxNum; i++) pallet[num[i].second] = i; int numSZ = num.size(); vector<Vec3i> color3i(numSZ); #pragma omp parallel for for (int i = 0; i < numSZ; i++) { color3i[i][0] = num[i].second / w[0]; color3i[i][1] = num[i].second % w[0] / w[1]; color3i[i][2] = num[i].second % w[1]; } for (unsigned int i = maxNum; i < num.size(); i++) { int simIdx = 0, simVal = INT_MAX; #pragma omp parallel for for (int j = 0; j < maxNum; j++) { int d_ij = vecSqrDist(color3i[i], color3i[j]); if (d_ij < simVal) simVal = d_ij, simIdx = j; } pallet[num[i].second] = pallet[num[simIdx].second]; } } _color3f = Mat::zeros(1, maxNum, CV_32FC3); _colorNum = Mat::zeros(_color3f.size(), CV_32S); Vec3f* color = (Vec3f*)(_color3f.data); int* colorNum = (int*)(_colorNum.data); for (int y = 0; y < rows; y++) { const Vec3f* imgData = img3f.ptr<Vec3f>(y); int* idx = idx1i.ptr<int>(y); #pragma omp parallel for for (int x = 0; x < cols; x++) idx[x] = pallet[idx[x]]; for (int x = 0; x < cols; x++) { color[idx[x]] += imgData[x]; colorNum[idx[x]] ++; } } for (int i = 0; i < _color3f.cols; i++) color[i] /= colorNum[i]; return _color3f.cols; }