/*! \ingroup group_imgproc_histogram Adjust the contrast of a color image by performing an histogram equalization. The intensity distribution is redistributed over the full [0 - 255] range such as the cumulative histogram distribution becomes linear. The alpha channel is ignored / copied from the source alpha channel. \param I : The color image to apply histogram equalization. \param useHSV : If true, the histogram equalization is performed on the value channel (in HSV space), otherwise the histogram equalization is performed independently on the RGB channels. */ void vp::equalizeHistogram(vpImage<vpRGBa> &I, const bool useHSV) { if(I.getWidth()*I.getHeight() == 0) { return; } if(!useHSV) { //Split the RGBa image into 4 images vpImage<unsigned char> pR(I.getHeight(), I.getWidth()); vpImage<unsigned char> pG(I.getHeight(), I.getWidth()); vpImage<unsigned char> pB(I.getHeight(), I.getWidth()); vpImage<unsigned char> pa(I.getHeight(), I.getWidth()); vpImageConvert::split(I, &pR, &pG, &pB, &pa); //Apply histogram equalization for each channel vp::equalizeHistogram(pR); vp::equalizeHistogram(pG); vp::equalizeHistogram(pB); //Merge the result in I unsigned int size = I.getWidth()*I.getHeight(); unsigned char *ptrStart = (unsigned char*) I.bitmap; unsigned char *ptrEnd = ptrStart + size*4; unsigned char *ptrCurrent = ptrStart; unsigned int cpt = 0; while(ptrCurrent != ptrEnd) { *ptrCurrent = pR.bitmap[cpt]; ++ptrCurrent; *ptrCurrent = pG.bitmap[cpt]; ++ptrCurrent; *ptrCurrent = pB.bitmap[cpt]; ++ptrCurrent; *ptrCurrent = pa.bitmap[cpt]; ++ptrCurrent; cpt++; } } else { vpImage<unsigned char> hue(I.getHeight(), I.getWidth()); vpImage<unsigned char> saturation(I.getHeight(), I.getWidth()); vpImage<unsigned char> value(I.getHeight(), I.getWidth()); unsigned int size = I.getWidth()*I.getHeight(); //Convert from RGBa to HSV vpImageConvert::RGBaToHSV((unsigned char *) I.bitmap, (unsigned char *) hue.bitmap, (unsigned char *) saturation.bitmap, (unsigned char *) value.bitmap, size); //Histogram equalization on the value plane vp::equalizeHistogram(value); //Convert from HSV to RGBa vpImageConvert::HSVToRGBa((unsigned char*) hue.bitmap, (unsigned char*) saturation.bitmap, (unsigned char*) value.bitmap, (unsigned char*) I.bitmap, size); } }
clsparseStatus cldenseDaxpy(cldenseVector *r, const clsparseScalar *alpha, const cldenseVector *x, const cldenseVector *y, const clsparseControl control) { if (!clsparseInitialized) { return clsparseNotInitialized; } //check opencl elements if (control == nullptr) { return clsparseInvalidControlObject; } clsparse::vector<cl_double> pR (control, r->values, r->num_values); clsparse::vector<cl_double> pAlpha(control, alpha->value, 1); clsparse::vector<cl_double> pX (control, x->values, x->num_values); clsparse::vector<cl_double> pY (control, y->values, y->num_values); assert(pR.size() == pY.size()); assert(pR.size() == pX.size()); cl_ulong size = pR.size(); if(size == 0) return clsparseSuccess; //nothing to do if (pAlpha[0] == 0.0) { auto pRBuff = pR.data()(); auto pYBuff = pY.data()(); //if R is different pointer than Y than copy Y to R if (pRBuff != pYBuff) { // deep copy; pR = pY; } return clsparseSuccess; } return axpy(pR, pAlpha, pX, pY, control); }
/*! \ingroup group_imgproc_contrast Stretch the contrast of a color image. \param I : The color image to stretch the contrast. */ void vp::stretchContrast(vpImage<vpRGBa> &I) { //Find min and max intensity values vpRGBa min = 255, max = 0; //Split the RGBa image into 4 images vpImage<unsigned char> pR(I.getHeight(), I.getWidth()); vpImage<unsigned char> pG(I.getHeight(), I.getWidth()); vpImage<unsigned char> pB(I.getHeight(), I.getWidth()); vpImage<unsigned char> pa(I.getHeight(), I.getWidth()); vpImageConvert::split(I, &pR, &pG, &pB, &pa); //Min max values calculated for each channel unsigned char minChannel, maxChannel; pR.getMinMaxValue(minChannel, maxChannel); min.R = minChannel; max.R = maxChannel; pG.getMinMaxValue(minChannel, maxChannel); min.G = minChannel; max.G = maxChannel; pB.getMinMaxValue(minChannel, maxChannel); min.B = minChannel; max.B = maxChannel; pa.getMinMaxValue(minChannel, maxChannel); min.A = minChannel; max.A = maxChannel; //Construct the look-up table vpRGBa lut[256]; unsigned char rangeR = max.R - min.R; if(rangeR > 0) { for(unsigned int x = min.R; x <= max.R; x++) { lut[x].R = 255 * (x - min.R) / rangeR; } } else { lut[min.R].R = min.R; } unsigned char rangeG = max.G - min.G; if(rangeG > 0) { for(unsigned int x = min.G; x <= max.G; x++) { lut[x].G = 255 * (x - min.G) / rangeG; } } else { lut[min.G].G = min.G; } unsigned char rangeB = max.B - min.B; if(rangeB > 0) { for(unsigned int x = min.B; x <= max.B; x++) { lut[x].B = 255 * (x - min.B) / rangeB; } } else { lut[min.B].B = min.B; } unsigned char rangeA = max.A - min.A; if(rangeA > 0) { for(unsigned int x = min.A; x <= max.A; x++) { lut[x].A = 255 * (x - min.A) / rangeA; } } else { lut[min.A].A = min.A; } I.performLut(lut); }
IplImage* getTone(const char *filename) { //实现论文中提到的正常铅笔画应有的直方图 double p1, p2, p3, p[256]; double temp = sqrt(2 * CV_PI * 10); for (int i = 0; i < 256; i++) { p1 = 1 / 9.0 * exp(-(256 - i) / 9.0); p2 = (i >= 105 && i <= 225) / (225 - 105.0); p3 = exp(-(i - 80)*(i - 80) / (2.0 * 10 * 10)) / temp; p[i] = 0.52 * p1 + 0.37 * p2 + 0.11 * p3; } smooth(p, 256); smooth(p, 256); double sum = 0; for (int i = 0; i < 256; i++) sum += p[i]; for (int i = 0; i < 256; i++) p[i] /= sum; double G[256]; G[0] = p[0]; for (int i = 1; i < 256; i++) G[i] = G[i - 1] + p[i]; //计算原图的直方图 IplImage *pToneImage = cvLoadImage(filename, CV_LOAD_IMAGE_GRAYSCALE); Image img(pToneImage); int h = pToneImage->height; int w = pToneImage->width; CvHistogram *pHis = CreateGrayImageHist(&pToneImage); double S[256]; S[0] = cvQueryHistValue_1D(pHis, 0) / (h*w); for (int i = 1; i < 256; i++) S[i] = S[i - 1] + cvQueryHistValue_1D(pHis, i) / (h*w); //进行直方图匹配 int index[256]; for (int i = 0; i < 256; i++) { int k = 0; for (int j = 1; j < 256; j++) if (abs(G[k] - S[i]) > abs(G[j] - S[i])) k = j; index[i] = k; } for (int i = 0; i < h; i++) for (int j = 0; j < w; j++) img[i][j] = index[img[i][j]]; //Pencil Texture Rendering IplImage *pRender = cvLoadImage("Tonal Texture.png", CV_LOAD_IMAGE_GRAYSCALE); Image pR(pRender); double **b = new double*[h]; for (int i = 0; i < h; i++) { b[i] = new double[w]; for (int j = 0; j < w; j++) { double H = pR[i % pR.getH()][j % pR.getW()] / 256.0; double J = img[i][j] / 256.0; double bx = (i) ? b[i - 1][j] : 0; double by = (j) ? b[i][j - 1] : 0; double A = 0.2 * 2 + log(H)*log(H); double B = -2*(0.2*(bx + by) + log(H)*log(J)); b[i][j] = -B / (2*A); img[i][j] = pow(H, b[i][j]) * 256; } } return pToneImage; }
bool SplitEvaluatorMLClass<Sample, TAppContext>::CalculateSpecificLossAndThreshold(DataSet<Sample, LabelMLClass>& dataset, std::vector<std::pair<double, int> > responses, std::pair<double, double>& score_and_threshold) { // In: samples, sorted responses, out:loss-value+threshold // 1) Calculate random thresholds and sort them double min_response = responses[0].first; double max_response = responses[responses.size()-1].first; double d = (max_response - min_response); vector<double> random_thresholds(m_appcontext->num_node_thresholds, 0.0); for (int i = 0; i < random_thresholds.size(); i++) random_thresholds[i] = (randDouble() * d) + min_response; sort(random_thresholds.begin(), random_thresholds.end()); // Declare and init some variables vector<double> RClassWeights(m_appcontext->num_classes, 0.0); vector<double> LClassWeights(m_appcontext->num_classes, 0.0); vector<int> RSamples; vector<int> LSamples; double RTotalWeight = 0.0; double LTotalWeight = 0.0; double margin = 0.0; double RLoss = 0.0, LLoss = 0.0; double BestLoss = 1e16, CombinedLoss = 0.0, TotalWeight = 0.0, BestThreshold = 0.0; bool found = false; // First, put everything in the right node RSamples.resize(responses.size()); for (int r = 0; r < responses.size(); r++) { int labelIdx = dataset[responses[r].second]->m_label.class_label; double sample_w = dataset[responses[r].second]->m_label.class_weight; RClassWeights[labelIdx] += sample_w; RTotalWeight += sample_w; RSamples[r] = responses[r].second; } // Now, iterate all responses and calculate Gini indices at the cutoff points (thresholds) int th_idx = 0; bool stop_search = false; for (int r = 0; r < responses.size(); r++) { // if the current sample is smaller than the current threshold put it to the left side if (responses[r].first <= random_thresholds[th_idx]) { int labelIdx = dataset[responses[r].second]->m_label.class_label; double cur_sample_weight = dataset[responses[r].second]->m_label.class_weight; RClassWeights[labelIdx] -= cur_sample_weight; if (RClassWeights[labelIdx] < 0.0) RClassWeights[labelIdx] = 0.0; LClassWeights[labelIdx] += cur_sample_weight; RTotalWeight -= cur_sample_weight; if (RTotalWeight < 0.0) RTotalWeight = 0.0; LTotalWeight += cur_sample_weight; LSamples.push_back(RSamples[0]); RSamples.erase(RSamples.begin()); } else { // ok, now we found the first sample having higher response than the current threshold // Reset the losses RLoss = 0.0, LLoss = 0.0; // calculate loss for left and right child nodes // RIGHT vector<double> pR(RClassWeights.size()); for (int ci = 0; ci < RClassWeights.size(); ci++) pR[ci] = RClassWeights[ci] / RTotalWeight; for (int ci = 0; ci < RClassWeights.size(); ci++) RLoss += RClassWeights[ci] * ComputeLoss(pR, ci, m_appcontext->global_loss_classification); // LEFT vector<double> pL(LClassWeights.size()); for (int ci = 0; ci < LClassWeights.size(); ci++) pL[ci] = LClassWeights[ci] / LTotalWeight; for (int ci = 0; ci < LClassWeights.size(); ci++) LLoss += LClassWeights[ci] * ComputeLoss(pL, ci, m_appcontext->global_loss_classification); // Total loss CombinedLoss = LLoss + RLoss; // best-search ... if (CombinedLoss < BestLoss && LTotalWeight > 0.0 && RTotalWeight > 0.0) { BestLoss = CombinedLoss; BestThreshold = random_thresholds[th_idx]; found = true; } // next, we have to find the next random threshold that is larger than the current response // -> there might be several threshold within the gap between the last response and this one. while (responses[r].first > random_thresholds[th_idx]) { if (th_idx < (random_thresholds.size()-1)) { th_idx++; r--; } else { stop_search = true; break; // all thresholds tested } } // now, we can go on with the next response ... } if (stop_search) break; } score_and_threshold.first = BestLoss; score_and_threshold.second = BestThreshold; return found; }