inline void FEGaussianBlur::platformApplyGeneric(ByteArray* srcPixelArray, ByteArray* tmpPixelArray, unsigned kernelSizeX, unsigned kernelSizeY, IntSize& paintSize) { int stride = 4 * paintSize.width(); int dxLeft = 0; int dxRight = 0; int dyLeft = 0; int dyRight = 0; for (int i = 0; i < 3; ++i) { if (kernelSizeX) { kernelPosition(i, kernelSizeX, dxLeft, dxRight); boxBlur(srcPixelArray, tmpPixelArray, kernelSizeX, dxLeft, dxRight, 4, stride, paintSize.width(), paintSize.height(), isAlphaImage()); } else { ByteArray* auxPixelArray = tmpPixelArray; tmpPixelArray = srcPixelArray; srcPixelArray = auxPixelArray; } if (kernelSizeY) { kernelPosition(i, kernelSizeY, dyLeft, dyRight); boxBlur(tmpPixelArray, srcPixelArray, kernelSizeY, dyLeft, dyRight, stride, 4, paintSize.height(), paintSize.width(), isAlphaImage()); } else { ByteArray* auxPixelArray = tmpPixelArray; tmpPixelArray = srcPixelArray; srcPixelArray = auxPixelArray; } } }
inline void FEGaussianBlur::platformApplyGeneric(Uint8ClampedArray* srcPixelArray, Uint8ClampedArray* tmpPixelArray, unsigned kernelSizeX, unsigned kernelSizeY, IntSize& paintSize) { int stride = 4 * paintSize.width(); int dxLeft = 0; int dxRight = 0; int dyLeft = 0; int dyRight = 0; Uint8ClampedArray* src = srcPixelArray; Uint8ClampedArray* dst = tmpPixelArray; for (int i = 0; i < 3; ++i) { if (kernelSizeX) { kernelPosition(i, kernelSizeX, dxLeft, dxRight); boxBlur(src, dst, kernelSizeX, dxLeft, dxRight, 4, stride, paintSize.width(), paintSize.height(), isAlphaImage()); swap(src, dst); } if (kernelSizeY) { kernelPosition(i, kernelSizeY, dyLeft, dyRight); boxBlur(src, dst, kernelSizeY, dyLeft, dyRight, stride, 4, paintSize.height(), paintSize.width(), isAlphaImage()); swap(src, dst); } } // The final result should be stored in srcPixelArray. if (dst == srcPixelArray) { ASSERT(src->length() == dst->length()); memcpy(dst->data(), src->data(), src->length()); } }
void FEGaussianBlur::apply(Filter* filter) { m_in->apply(filter); if (!m_in->resultImage()) return; if (!getEffectContext()) return; setIsAlphaImage(m_in->isAlphaImage()); if (m_x == 0 || m_y == 0) return; unsigned sdx = static_cast<unsigned>(floor(m_x * 3 * sqrt(2 * M_PI) / 4.f + 0.5f)); unsigned sdy = static_cast<unsigned>(floor(m_y * 3 * sqrt(2 * M_PI) / 4.f + 0.5f)); IntRect effectDrawingRect = calculateDrawingIntRect(m_in->subRegion()); RefPtr<ImageData> srcImageData(m_in->resultImage()->getPremultipliedImageData(effectDrawingRect)); CanvasPixelArray* srcPixelArray(srcImageData->data()); IntRect imageRect(IntPoint(), resultImage()->size()); RefPtr<ImageData> tmpImageData = ImageData::create(imageRect.width(), imageRect.height()); CanvasPixelArray* tmpPixelArray(tmpImageData->data()); int stride = 4 * imageRect.width(); for (int i = 0; i < 3; ++i) { boxBlur(srcPixelArray, tmpPixelArray, sdx, 4, stride, imageRect.width(), imageRect.height(), isAlphaImage()); boxBlur(tmpPixelArray, srcPixelArray, sdy, stride, 4, imageRect.height(), imageRect.width(), isAlphaImage()); } resultImage()->putPremultipliedImageData(srcImageData.get(), imageRect, IntPoint()); }
void GaussianBlur::gaussBlur(IntensityMap &input, IntensityMap &result, double radius, bool tileable) { std::vector<double> boxes = boxesForGauss(radius, 3); boxBlur(input, result, ((boxes.at(0) - 1) / 2), tileable); boxBlur(result, input, ((boxes.at(1) - 1) / 2), tileable); boxBlur(input, result, ((boxes.at(2) - 1) / 2), tileable); }
dtStatus dtBuildTileCacheDistanceField(dtTileCacheAlloc* alloc, dtTileCacheLayer& layer, dtTileCacheDistanceField& dfield) { dtAssert(alloc); const int w = (int)layer.header->width; const int h = (int)layer.header->height; dfield.data = (unsigned short*)alloc->alloc(w*h*sizeof(unsigned short)); if (!dfield.data) { return DT_FAILURE | DT_OUT_OF_MEMORY; } dtTileCacheDistanceField tmpField; tmpField.data = (unsigned short*)alloc->alloc(w*h*sizeof(unsigned short)); if (!tmpField.data) { return DT_FAILURE | DT_OUT_OF_MEMORY; } calculateDistanceField(layer, dfield.data, dfield.maxDist); if (boxBlur(layer, 1, dfield.data, tmpField.data) != dfield.data) { dtSwap(dfield.data, tmpField.data); } alloc->free(tmpField.data); return DT_SUCCESS; }
inline void standardBoxBlur(Uint8ClampedArray* src, Uint8ClampedArray* dst, unsigned kernelSizeX, unsigned kernelSizeY, int stride, IntSize& paintSize, bool isAlphaImage, EdgeModeType edgeMode) { int dxLeft = 0; int dxRight = 0; int dyLeft = 0; int dyRight = 0; for (int i = 0; i < 3; ++i) { if (kernelSizeX) { kernelPosition(i, kernelSizeX, dxLeft, dxRight); #if HAVE(ARM_NEON_INTRINSICS) if (!isAlphaImage) boxBlurNEON(src, dst, kernelSizeX, dxLeft, dxRight, 4, stride, paintSize.width(), paintSize.height()); else boxBlur(src, dst, kernelSizeX, dxLeft, dxRight, 4, stride, paintSize.width(), paintSize.height(), true, edgeMode); #else boxBlur(src, dst, kernelSizeX, dxLeft, dxRight, 4, stride, paintSize.width(), paintSize.height(), isAlphaImage, edgeMode); #endif std::swap(src, dst); } if (kernelSizeY) { kernelPosition(i, kernelSizeY, dyLeft, dyRight); #if HAVE(ARM_NEON_INTRINSICS) if (!isAlphaImage) boxBlurNEON(src, dst, kernelSizeY, dyLeft, dyRight, stride, 4, paintSize.height(), paintSize.width()); else boxBlur(src, dst, kernelSizeY, dyLeft, dyRight, stride, 4, paintSize.height(), paintSize.width(), true, edgeMode); #else boxBlur(src, dst, kernelSizeY, dyLeft, dyRight, stride, 4, paintSize.height(), paintSize.width(), isAlphaImage, edgeMode); #endif std::swap(src, dst); } } // The final result should be stored in src. if (dst == src) { ASSERT(src->length() == dst->length()); memcpy(dst->data(), src->data(), src->length()); } }
// ###################################################################### Image<float> ContourBoundaryDetector::getLabStandardDeviation (Image<PixRGB<byte> > ima, int r) { // convert to CIElab color space Image<float> lImg; Image<float> aImg; Image<float> bImg; getLAB(ima, lImg, aImg, bImg); // compute squares of each channel Image<float> lSqImg = lImg * lImg; Image<float> aSqImg = aImg * aImg; Image<float> bSqImg = bImg * bImg; // compute box blur for each channel Image<float> lBbImg = boxBlur(lImg, r); Image<float> aBbImg = boxBlur(aImg, r); Image<float> bBbImg = boxBlur(bImg, r); Image<float> lSqBbImg = boxBlur(lSqImg, r); Image<float> aSqBbImg = boxBlur(aSqImg, r); Image<float> bSqBbImg = boxBlur(bSqImg, r); //calculate standard deviation of each l a b channel Image<float> vl = lBbImg*lBbImg - lSqBbImg; Image<float> va = aBbImg*aBbImg - aSqBbImg; Image<float> vb = bBbImg*bBbImg - bSqBbImg; Image<float> varImg = sqCombine(vl, va, vb); return varImg; }
/// @par /// /// This is usually the second to the last step in creating a fully built /// compact heightfield. This step is required before regions are built /// using #rcBuildRegions or #rcBuildRegionsMonotone. /// /// After this step, the distance data is available via the rcCompactHeightfield::maxDistance /// and rcCompactHeightfield::dist fields. /// /// @see rcCompactHeightfield, rcBuildRegions, rcBuildRegionsMonotone bool rcBuildDistanceField(rcContext* ctx, rcCompactHeightfield& chf) { rcAssert(ctx); ctx->startTimer(RC_TIMER_BUILD_DISTANCEFIELD); if (chf.dist) { rcFree(chf.dist); chf.dist = 0; } unsigned short* src = (unsigned short*)rcAlloc(sizeof(unsigned short)*chf.spanCount, RC_ALLOC_TEMP); if (!src) { ctx->log(RC_LOG_ERROR, "rcBuildDistanceField: Out of memory 'src' (%d).", chf.spanCount); return false; } unsigned short* dst = (unsigned short*)rcAlloc(sizeof(unsigned short)*chf.spanCount, RC_ALLOC_TEMP); if (!dst) { ctx->log(RC_LOG_ERROR, "rcBuildDistanceField: Out of memory 'dst' (%d).", chf.spanCount); rcFree(src); return false; } unsigned short maxDist = 0; ctx->startTimer(RC_TIMER_BUILD_DISTANCEFIELD_DIST); calculateDistanceField(chf, src, maxDist); chf.maxDistance = maxDist; ctx->stopTimer(RC_TIMER_BUILD_DISTANCEFIELD_DIST); ctx->startTimer(RC_TIMER_BUILD_DISTANCEFIELD_BLUR); // Blur if (boxBlur(chf, 1, src, dst) != src) rcSwap(src, dst); // Store distance. chf.dist = src; ctx->stopTimer(RC_TIMER_BUILD_DISTANCEFIELD_BLUR); ctx->stopTimer(RC_TIMER_BUILD_DISTANCEFIELD); rcFree(dst); return true; }
/// @par /// /// This is usually the second to the last step in creating a fully built /// compact heightfield. This step is required before regions are built /// using #rcBuildRegions or #rcBuildRegionsMonotone. /// /// After this step, the distance data is available via the rcCompactHeightfield::maxDistance /// and rcCompactHeightfield::dist fields. /// /// @see rcCompactHeightfield, rcBuildRegions, rcBuildRegionsMonotone bool rcBuildDistanceField(rcCompactHeightfield& chf) { if (chf.dist) { rcFree(chf.dist); chf.dist = 0; } unsigned short* src = (unsigned short*)rcAlloc(sizeof(unsigned short)*chf.spanCount, RC_ALLOC_TEMP); if (!src) { return false; } unsigned short* dst = (unsigned short*)rcAlloc(sizeof(unsigned short)*chf.spanCount, RC_ALLOC_TEMP); if (!dst) { rcFree(src); return false; } unsigned short maxDist = 0; calculateDistanceField(chf, src, maxDist); chf.maxDistance = maxDist; // Blur if (boxBlur(chf, 1, src, dst) != src) rcSwap(src, dst); // Store distance. chf.dist = src; rcFree(dst); return true; }
bool SkBlurMask::Blur(SkMask* dst, const SkMask& src, SkScalar radius, Style style, Quality quality, SkIPoint* margin) { if (src.fFormat != SkMask::kA8_Format) { return false; } // Force high quality off for small radii (performance) if (radius < SkIntToScalar(3)) { quality = kLow_Quality; } // highQuality: use three box blur passes as a cheap way // to approximate a Gaussian blur int passCount = (kHigh_Quality == quality) ? 3 : 1; SkScalar passRadius = (kHigh_Quality == quality) ? SkScalarMul( radius, kBlurRadiusFudgeFactor): radius; int rx = SkScalarCeil(passRadius); int outerWeight = 255 - SkScalarRound((SkIntToScalar(rx) - passRadius) * 255); SkASSERT(rx >= 0); SkASSERT((unsigned)outerWeight <= 255); if (rx <= 0) { return false; } int ry = rx; // only do square blur for now int padx = passCount * rx; int pady = passCount * ry; if (margin) { margin->set(padx, pady); } dst->fBounds.set(src.fBounds.fLeft - padx, src.fBounds.fTop - pady, src.fBounds.fRight + padx, src.fBounds.fBottom + pady); dst->fRowBytes = dst->fBounds.width(); dst->fFormat = SkMask::kA8_Format; dst->fImage = NULL; if (src.fImage) { size_t dstSize = dst->computeImageSize(); if (0 == dstSize) { return false; // too big to allocate, abort } int sw = src.fBounds.width(); int sh = src.fBounds.height(); const uint8_t* sp = src.fImage; uint8_t* dp = SkMask::AllocImage(dstSize); SkAutoTCallVProc<uint8_t, SkMask_FreeImage> autoCall(dp); // build the blurry destination SkAutoTMalloc<uint8_t> tmpBuffer(dstSize); uint8_t* tp = tmpBuffer.get(); int w = sw, h = sh; if (outerWeight == 255) { int loRadius, hiRadius; get_adjusted_radii(passRadius, &loRadius, &hiRadius); if (kHigh_Quality == quality) { // Do three X blurs, with a transpose on the final one. w = boxBlur(sp, src.fRowBytes, tp, loRadius, hiRadius, w, h, false); w = boxBlur(tp, w, dp, hiRadius, loRadius, w, h, false); w = boxBlur(dp, w, tp, hiRadius, hiRadius, w, h, true); // Do three Y blurs, with a transpose on the final one. h = boxBlur(tp, h, dp, loRadius, hiRadius, h, w, false); h = boxBlur(dp, h, tp, hiRadius, loRadius, h, w, false); h = boxBlur(tp, h, dp, hiRadius, hiRadius, h, w, true); } else { w = boxBlur(sp, src.fRowBytes, tp, rx, rx, w, h, true); h = boxBlur(tp, h, dp, ry, ry, h, w, true); } } else { if (kHigh_Quality == quality) { // Do three X blurs, with a transpose on the final one. w = boxBlurInterp(sp, src.fRowBytes, tp, rx, w, h, false, outerWeight); w = boxBlurInterp(tp, w, dp, rx, w, h, false, outerWeight); w = boxBlurInterp(dp, w, tp, rx, w, h, true, outerWeight); // Do three Y blurs, with a transpose on the final one. h = boxBlurInterp(tp, h, dp, ry, h, w, false, outerWeight); h = boxBlurInterp(dp, h, tp, ry, h, w, false, outerWeight); h = boxBlurInterp(tp, h, dp, ry, h, w, true, outerWeight); } else { w = boxBlurInterp(sp, src.fRowBytes, tp, rx, w, h, true, outerWeight); h = boxBlurInterp(tp, h, dp, ry, h, w, true, outerWeight); } } dst->fImage = dp; // if need be, alloc the "real" dst (same size as src) and copy/merge // the blur into it (applying the src) if (style == kInner_Style) { // now we allocate the "real" dst, mirror the size of src size_t srcSize = src.computeImageSize(); if (0 == srcSize) { return false; // too big to allocate, abort } dst->fImage = SkMask::AllocImage(srcSize); merge_src_with_blur(dst->fImage, src.fRowBytes, sp, src.fRowBytes, dp + passCount * (rx + ry * dst->fRowBytes), dst->fRowBytes, sw, sh); SkMask::FreeImage(dp); } else if (style != kNormal_Style) { clamp_with_orig(dp + passCount * (rx + ry * dst->fRowBytes), dst->fRowBytes, sp, src.fRowBytes, sw, sh, style); } (void)autoCall.detach(); } if (style == kInner_Style) { dst->fBounds = src.fBounds; // restore trimmed bounds dst->fRowBytes = src.fRowBytes; } return true; }
bool rcBuildDistanceField(rcCompactHeightfield& chf) { rcTimeVal startTime = rcGetPerformanceTimer(); unsigned short* dist0 = new unsigned short[chf.spanCount]; if (!dist0) { if (rcGetLog()) rcGetLog()->log(RC_LOG_ERROR, "rcBuildDistanceField: Out of memory 'dist0' (%d).", chf.spanCount); return false; } unsigned short* dist1 = new unsigned short[chf.spanCount]; if (!dist1) { if (rcGetLog()) rcGetLog()->log(RC_LOG_ERROR, "rcBuildDistanceField: Out of memory 'dist1' (%d).", chf.spanCount); delete [] dist0; return false; } unsigned short* src = dist0; unsigned short* dst = dist1; unsigned short maxDist = 0; rcTimeVal distStartTime = rcGetPerformanceTimer(); if (calculateDistanceField(chf, src, dst, maxDist) != src) rcSwap(src, dst); chf.maxDistance = maxDist; rcTimeVal distEndTime = rcGetPerformanceTimer(); rcTimeVal blurStartTime = rcGetPerformanceTimer(); // Blur if (boxBlur(chf, 1, src, dst) != src) rcSwap(src, dst); // Store distance. for (int i = 0; i < chf.spanCount; ++i) chf.spans[i].dist = src[i]; rcTimeVal blurEndTime = rcGetPerformanceTimer(); delete [] dist0; delete [] dist1; rcTimeVal endTime = rcGetPerformanceTimer(); /* if (rcGetLog()) { rcGetLog()->log(RC_LOG_PROGRESS, "Build distance field: %.3f ms", rcGetDeltaTimeUsec(startTime, endTime)/1000.0f); rcGetLog()->log(RC_LOG_PROGRESS, " - dist: %.3f ms", rcGetDeltaTimeUsec(distStartTime, distEndTime)/1000.0f); rcGetLog()->log(RC_LOG_PROGRESS, " - blur: %.3f ms", rcGetDeltaTimeUsec(blurStartTime, blurEndTime)/1000.0f); }*/ if (rcGetBuildTimes()) { rcGetBuildTimes()->buildDistanceField += rcGetDeltaTimeUsec(startTime, endTime); rcGetBuildTimes()->buildDistanceFieldDist += rcGetDeltaTimeUsec(distStartTime, distEndTime); rcGetBuildTimes()->buildDistanceFieldBlur += rcGetDeltaTimeUsec(blurStartTime, blurEndTime); } return true; }
bool MCGBlurBox(const SkMask& p_src, SkScalar p_x_radius, SkScalar p_y_radius, SkScalar p_x_spread, SkScalar p_y_spread, SkMask& r_dst) { int t_pass_count; t_pass_count = 3; // Maximum amount of spread is 254 pixels. int x_spread, y_spread; x_spread = SkMin32(SkScalarFloor(p_x_radius * p_x_spread), 254); y_spread = SkMin32(SkScalarFloor(p_y_radius * p_y_spread), 254); p_x_radius -= x_spread; p_y_radius -= y_spread; int rx, ry; rx = SkScalarCeil(p_x_radius); ry = SkScalarCeil(p_y_radius); SkScalar px, py; px = rx; py = ry; int wx, wy; wx = 255 - SkScalarRound((SkIntToScalar(rx) - px) * 255); wy = 255 - SkScalarRound((SkIntToScalar(ry) - py) * 255); int t_pad_x, t_pad_y; t_pad_x = rx + x_spread; t_pad_y = ry + y_spread; r_dst . fBounds . set(p_src . fBounds . fLeft - t_pad_x, p_src . fBounds . fTop - t_pad_y, p_src . fBounds . fRight + t_pad_x, p_src . fBounds . fBottom + t_pad_y); r_dst . fRowBytes = r_dst . fBounds . width(); r_dst . fFormat = SkMask::kA8_Format; r_dst . fImage = NULL; if (p_src . fImage == NULL) return true; size_t t_dst_size; t_dst_size = r_dst . computeImageSize(); if (t_dst_size == 0) return false; int sw, sh; sw = p_src . fBounds . width(); sh = p_src . fBounds . height(); const uint8_t *sp; sp = p_src . fImage; uint8_t *dp; dp = SkMask::AllocImage(t_dst_size); if (dp == nil) return false; uint8_t *tp; tp = SkMask::AllocImage(t_dst_size); if (tp == nil) { SkMask::FreeImage(dp); return false; } int w, h; w = sw; h = sh; if (wx == 255) { if (t_pass_count == 3) { int r; r = rx; bool t_has_spread; t_has_spread = false; if (x_spread != 0 || y_spread != 0) { //w = dilateMask(sp, p_src . fRowBytes, tp, x_spread, w, h, true); //h = dilateMask(tp, h, dp, y_spread, h, w, true); dilateDistanceXY(sp, dp, x_spread, y_spread, w, h, w, h); t_has_spread = true; } int trx; trx = (r + 2) / 3; r -= trx; int rx_lo, rx_hi; rx_lo = rx_hi = trx; w = boxBlur(t_has_spread ? dp : sp, t_has_spread ? w : p_src . fRowBytes, tp, rx_lo, rx_hi, w, h, false); trx = (r + 1) / 2; r -= trx; rx_lo = rx_hi = trx; w = boxBlur(tp, w, dp, rx_hi, rx_lo, w, h, false); trx = r; rx_lo = rx_hi = trx; w = boxBlur(dp, w, tp, rx_hi, rx_hi, w, h, true); } else w = boxBlur(sp, p_src . fRowBytes, tp, rx, rx, w, h, true); } else { if (t_pass_count == 3) { int r; r = rx; bool t_has_spread; t_has_spread = false; if (x_spread != 0 || y_spread != 0) { //w = dilateMask(sp, p_src . fRowBytes, tp, x_spread, w, h, true); //h = dilateMask(tp, h, dp, y_spread, h, w, true); dilateDistanceXY(sp, dp, x_spread, y_spread, w, h, w, h); t_has_spread = true; } int trx; trx = (r + 2) / 3; r -= trx; w = boxBlurInterp(t_has_spread ? dp : sp, t_has_spread ? w : p_src . fRowBytes, tp, trx, w, h, false, wx); trx = (r + 1) / 2; r -= trx; w = boxBlurInterp(tp, w, dp, trx, w, h, false, wx); trx = r; w = boxBlurInterp(dp, w, tp, trx, w, h, true, wx); } else w = boxBlurInterp(sp, p_src . fRowBytes, tp, rx, w, h, true, wx); } if (wy == 255) { if (t_pass_count == 3) { int r; r = ry; int sry; sry = (r + 2) / 3; r -= sry; int ry_lo, ry_hi; ry_lo = ry_hi = sry; h = boxBlur(tp, h, dp, ry_lo, ry_hi, h, w, false); sry = (r + 1) / 2; r -= sry; ry_lo = ry_hi = sry; h = boxBlur(dp, h, tp, ry_hi, ry_lo, h, w, false); sry = r; ry_lo = ry_hi = sry; h = boxBlur(tp, h, dp, ry_hi, ry_hi, h, w, true); } else h = boxBlur(tp, h, dp, ry, ry, h, w, true); } else { if (t_pass_count == 3) { int r; r = ry; int sry; sry = (r + 2) / 3; r -= sry; h = boxBlurInterp(tp, h, dp, sry, h, w, false, wy); sry = (r + 1) / 2; r -= sry; h = boxBlurInterp(dp, h, tp, sry, h, w, false, wy); sry = r; h = boxBlurInterp(tp, h, dp, sry, h, w, true, wy); } else w = boxBlurInterp(tp, h, dp, rx, h, w, true, wy); } SkMask::FreeImage(tp); r_dst . fImage = dp; return true; }
// ###################################################################### std::vector<Image<float> > ContourBoundaryDetector::calculateGradient (Image<float> varImg, int r) { int w = varImg.getWidth(); int h = varImg.getHeight(); Image<float> gradImgX(w,h,NO_INIT); Image<float> gradImgY(w,h,NO_INIT); // smooth the variance Image using BoxBlur Image<float> varBbImg = boxBlur(varImg, r); std::vector<float> dx(NUM_GRADIENT_DIRECTIONS); std::vector<float> dy(NUM_GRADIENT_DIRECTIONS); for(uint k = 0; k < NUM_GRADIENT_DIRECTIONS; k++) { dx[k] = cos(k*2*M_PI/NUM_GRADIENT_DIRECTIONS); dy[k] = sin(k*2*M_PI/NUM_GRADIENT_DIRECTIONS); LDEBUG("%d %f %f", k, dx[k], dy[k]); } // go through each location for(int i = 0; i < w; i++) { for(int j = 0; j < h; j++) { float sumX = 0.0; float sumY = 0.0; for(uint k = 0; k < NUM_GRADIENT_DIRECTIONS; k++) { int i1 = i + r*dx[k]; int j1 = j + r*dy[k]; int i2 = i - r*dx[k]; int j2 = j - r*dy[k]; // pixel mirroring at the image borders if(i1 < 0) i1 = -i1; if(j1 < 0) j1 = -j1; if(i1 >= w) i1 = 2*w - 2 - i1; if(j1 >= h) j1 = 2*h - 2 - j1; if(i2 < 0) i2 = -i2; if(j2 < 0) j2 = -j2; if(i2 >= w) i2 = 2*w - 2 - i2; if(j2 >= h) j2 = 2*h - 2 - j2; float val = varBbImg.getVal(i1,j1) - varBbImg.getVal(i2,j2); sumX += val * dx[k]; sumY += val * dy[k]; // LINFO("%d %d %d| val: %f, (%f %f) %f %f", // i,j,k, val, val*dx[k], val*dy[k], sumX, sumY); } gradImgX.setVal(i,j, sumX); gradImgY.setVal(i,j, sumY); } } std::vector<Image<float> > gradImg(2); gradImg[0] = gradImgX; gradImg[1] = gradImgY; return gradImg; }