| |
| |
| #include "stdfx.h" |
| #include "tfxparam.h" |
| #include "trop.h" |
| #include "tdoubleparam.h" |
| #include "trasterfx.h" |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| namespace { |
| |
| struct Sums { |
| std::unique_ptr<TUINT64[]> |
| m_sumsIX_r; |
| std::unique_ptr<TUINT64[]> m_sumsIX_g; |
| std::unique_ptr<TUINT64[]> m_sumsIX_b; |
| std::unique_ptr<TUINT64[]> m_sumsIX_m; |
| std::unique_ptr<TUINT64[]> m_sumsX_r; |
| std::unique_ptr<TUINT64[]> m_sumsX_g; |
| std::unique_ptr<TUINT64[]> m_sumsX_b; |
| std::unique_ptr<TUINT64[]> m_sumsX_m; |
| |
| Sums(int length) |
| : m_sumsIX_r(new TUINT64[length + 1]) |
| , m_sumsIX_g(new TUINT64[length + 1]) |
| , m_sumsIX_b(new TUINT64[length + 1]) |
| , m_sumsIX_m(new TUINT64[length + 1]) |
| , m_sumsX_r(new TUINT64[length + 1]) |
| , m_sumsX_g(new TUINT64[length + 1]) |
| , m_sumsX_b(new TUINT64[length + 1]) |
| , m_sumsX_m(new TUINT64[length + 1]) {} |
| |
| template <typename Pix> |
| void build(Pix *line, int wrap, int n) { |
| ++n; |
| |
| m_sumsIX_r[0] = m_sumsX_r[0] = 0; |
| m_sumsIX_g[0] = m_sumsX_g[0] = 0; |
| m_sumsIX_b[0] = m_sumsX_b[0] = 0; |
| m_sumsIX_m[0] = m_sumsX_m[0] = 0; |
| |
| Pix *pix; |
| int i, i_1; |
| |
| for (pix = line, i_1 = 0, i = 1; i < n; pix += wrap, i_1 = i++) { |
| m_sumsIX_r[i] = m_sumsIX_r[i_1] + i * pix->r; |
| m_sumsIX_g[i] = m_sumsIX_g[i_1] + i * pix->g; |
| m_sumsIX_b[i] = m_sumsIX_b[i_1] + i * pix->b; |
| m_sumsIX_m[i] = m_sumsIX_m[i_1] + i * pix->m; |
| |
| m_sumsX_r[i] = m_sumsX_r[i_1] + pix->r; |
| m_sumsX_g[i] = m_sumsX_g[i_1] + pix->g; |
| m_sumsX_b[i] = m_sumsX_b[i_1] + pix->b; |
| m_sumsX_m[i] = m_sumsX_m[i_1] + pix->m; |
| } |
| } |
| }; |
| |
| |
| |
| template <typename Pix, typename Grey> |
| void filterLine(Pix *lineIn, int wrapIn, Grey *lineGr, int wrapGr, Pix *lineOut, |
| int wrapOut, int length, double blurFactor, Sums &sums) { |
| |
| sums.build(lineIn, wrapIn, length); |
| |
| |
| double blur, kLeft, kRight, cLeft, cRight; |
| double blurI; |
| |
| |
| Pix *pixIn, *pixOut; |
| Grey *pixGr; |
| |
| int i, iLeft, iRight; |
| ++length; |
| |
| for (i = 1, pixIn = lineIn, pixGr = lineGr, pixOut = lineOut; i < length; |
| ++i, pixIn += wrapIn, pixGr += wrapGr, pixOut += wrapOut) { |
| blur = pixGr->value * blurFactor; |
| |
| |
| if (blur > 0.0) { |
| blur += |
| 0.5; |
| |
| |
| |
| blurI = (double)tfloor(blur); |
| |
| double amount = blur + (2 * blur - blurI - 1) * blurI; |
| |
| double dR = 1.0 / amount; |
| double ini = (blur - blurI) / amount; |
| |
| kLeft = dR; |
| cLeft = ini - dR * (i - blurI); |
| kRight = -dR; |
| cRight = blur / amount + dR * i; |
| |
| |
| |
| |
| |
| iLeft = std::max(i - tfloor(blur) - 1, 0); |
| iRight = std::min(i + tfloor(blur), length - 1); |
| |
| pixOut->r = |
| troundp(kLeft * (sums.m_sumsIX_r[i] - sums.m_sumsIX_r[iLeft]) + |
| kRight * (sums.m_sumsIX_r[iRight] - sums.m_sumsIX_r[i]) + |
| cLeft * (sums.m_sumsX_r[i] - sums.m_sumsX_r[iLeft]) + |
| cRight * (sums.m_sumsX_r[iRight] - sums.m_sumsX_r[i])); |
| pixOut->g = |
| troundp(kLeft * (sums.m_sumsIX_g[i] - sums.m_sumsIX_g[iLeft]) + |
| kRight * (sums.m_sumsIX_g[iRight] - sums.m_sumsIX_g[i]) + |
| cLeft * (sums.m_sumsX_g[i] - sums.m_sumsX_g[iLeft]) + |
| cRight * (sums.m_sumsX_g[iRight] - sums.m_sumsX_g[i])); |
| pixOut->b = |
| troundp(kLeft * (sums.m_sumsIX_b[i] - sums.m_sumsIX_b[iLeft]) + |
| kRight * (sums.m_sumsIX_b[iRight] - sums.m_sumsIX_b[i]) + |
| cLeft * (sums.m_sumsX_b[i] - sums.m_sumsX_b[iLeft]) + |
| cRight * (sums.m_sumsX_b[iRight] - sums.m_sumsX_b[i])); |
| pixOut->m = |
| troundp(kLeft * (sums.m_sumsIX_m[i] - sums.m_sumsIX_m[iLeft]) + |
| kRight * (sums.m_sumsIX_m[iRight] - sums.m_sumsIX_m[i]) + |
| cLeft * (sums.m_sumsX_m[i] - sums.m_sumsX_m[iLeft]) + |
| cRight * (sums.m_sumsX_m[iRight] - sums.m_sumsX_m[i])); |
| } else |
| *pixOut = *pixIn; |
| } |
| } |
| |
| |
| |
| template <typename Pix, typename Grey> |
| void doLocalBlur(TRasterPT<Pix> rin, TRasterPT<Pix> rcontrol, |
| TRasterPT<Pix> rout, double blur, const TPoint &displacement) { |
| assert(rin->getLx() == rcontrol->getLx() && |
| rin->getLy() == rcontrol->getLy()); |
| |
| double blurFactor = blur / Grey::maxChannelValue; |
| |
| int x, y, inLx, inLy, outLx, outLy, wrapIn, wrapOut, wrapC; |
| |
| inLx = rin->getLx(); |
| inLy = rin->getLy(); |
| wrapIn = rin->getWrap(); |
| outLx = rout->getLx(); |
| outLy = rout->getLy(); |
| wrapOut = rout->getWrap(); |
| |
| |
| |
| |
| TRasterPT<Grey> rcontrolGrey(rcontrol->getLx(), rcontrol->getLy()); |
| TRop::convert(rcontrolGrey, rcontrol); |
| |
| wrapC = rcontrolGrey->getWrap(); |
| |
| Pix *lineIn, *bufIn; |
| Grey *lineC, *bufC; |
| |
| |
| |
| rin->lock(); |
| rcontrolGrey->lock(); |
| |
| bufIn = rin->pixels(0); |
| bufC = rcontrolGrey->pixels(0); |
| |
| { |
| Sums sums(inLx); |
| |
| for (y = 0, lineIn = bufIn, lineC = bufC; y < inLy; |
| ++y, lineIn += wrapIn, lineC += wrapC) { |
| |
| filterLine(lineIn, 1, lineC, 1, lineIn, 1, inLx, blurFactor, sums); |
| } |
| } |
| |
| { |
| Sums sums(inLy); |
| |
| for (x = 0, lineIn = bufIn, lineC = bufC; x < inLx; |
| ++x, ++lineIn, ++lineC) { |
| |
| filterLine(lineIn, wrapIn, lineC, wrapC, lineIn, wrapIn, inLy, blurFactor, |
| sums); |
| } |
| } |
| |
| rin->unlock(); |
| rcontrolGrey->unlock(); |
| |
| |
| TRect rectOut(rout->getBounds() - displacement); |
| TRect rectIn(rin->getBounds() + displacement); |
| |
| TRop::copy(rout->extract(rectIn), rin->extract(rectOut)); |
| } |
| |
| } |
| |
| |
| |
| |
| |
| class LocalBlurFx final : public TStandardRasterFx { |
| FX_PLUGIN_DECLARATION(LocalBlurFx) |
| |
| protected: |
| TRasterFxPort m_up, m_ref; |
| TDoubleParamP m_value; |
| |
| public: |
| LocalBlurFx() : m_value(20) { |
| m_value->setMeasureName("fxLength"); |
| addInputPort("Source", m_up); |
| addInputPort("Reference", m_ref); |
| bindParam(this, "value", m_value); |
| m_value->setValueRange(0, (std::numeric_limits<double>::max)()); |
| } |
| |
| ~LocalBlurFx() {} |
| |
| bool canHandle(const TRenderSettings &info, double frame) override { |
| return (isAlmostIsotropic(info.m_affine) || m_value->getValue(frame) == 0); |
| } |
| |
| bool doGetBBox(double frame, TRectD &bBox, |
| const TRenderSettings &info) override { |
| if (m_up.isConnected()) { |
| bool ret = m_up->doGetBBox(frame, bBox, info); |
| |
| double blur = fabs(m_value->getValue(frame)); |
| int blurI = tceil(blur); |
| bBox = bBox.enlarge(blurI); |
| |
| return ret; |
| } else { |
| bBox = TRectD(); |
| return false; |
| } |
| } |
| |
| void enlarge(const TRectD &bbox, TRectD &requestedRect, int blur); |
| |
| void doDryCompute(TRectD &rect, double frame, |
| const TRenderSettings &info) override; |
| void doCompute(TTile &tile, double frame, |
| const TRenderSettings &info) override; |
| |
| int getMemoryRequirement(const TRectD &rect, double frame, |
| const TRenderSettings &info) override; |
| }; |
| |
| |
| |
| void LocalBlurFx::enlarge(const TRectD &bbox, TRectD &requestedRect, int blur) { |
| |
| if (bbox.isEmpty() || requestedRect.isEmpty()) { |
| requestedRect.empty(); |
| return; |
| } |
| |
| TRectD enlargedBBox(bbox.enlarge(blur)); |
| TRectD enlargedOut(requestedRect.enlarge(blur)); |
| |
| TPointD originalP00(requestedRect.getP00()); |
| requestedRect = (enlargedOut * bbox) + (enlargedBBox * requestedRect); |
| |
| requestedRect -= originalP00; |
| requestedRect.x0 = tfloor(requestedRect.x0); |
| requestedRect.y0 = tfloor(requestedRect.y0); |
| requestedRect.x1 = tceil(requestedRect.x1); |
| requestedRect.y1 = tceil(requestedRect.y1); |
| requestedRect += originalP00; |
| } |
| |
| |
| |
| void LocalBlurFx::doDryCompute(TRectD &rectOut, double frame, |
| const TRenderSettings &info) { |
| |
| |
| TTile refTile; |
| bool isUp = m_up.isConnected(); |
| bool isDown = m_ref.isConnected(); |
| |
| if (!isUp) return; |
| |
| if (!isDown) { |
| m_up->dryCompute(rectOut, frame, info); |
| return; |
| } |
| |
| double blur = |
| fabs(m_value->getValue(frame) * sqrt(fabs(info.m_affine.det()))); |
| int blurI = tceil(blur); |
| |
| TRectD bboxIn; |
| if (!m_up->getBBox(frame, bboxIn, info) || rectOut.isEmpty()) return; |
| |
| TRectD rectIn(rectOut); |
| enlarge(bboxIn, rectIn, blurI); |
| |
| if (rectIn.isEmpty()) return; |
| |
| m_up->dryCompute(rectOut, frame, info); |
| m_ref->dryCompute(rectOut, frame, info); |
| } |
| |
| |
| |
| void LocalBlurFx::doCompute(TTile &tile, double frame, |
| const TRenderSettings &info) { |
| TTile refTile; |
| bool isUp = m_up.isConnected(); |
| bool isDown = m_ref.isConnected(); |
| |
| if (!isUp) return; |
| |
| if (!isDown) { |
| m_up->compute(tile, frame, info); |
| return; |
| } |
| |
| |
| assert(isAlmostIsotropic(info.m_affine)); |
| double blur = |
| fabs(m_value->getValue(frame) * sqrt(fabs(info.m_affine.det()))); |
| int blurI = tceil(blur); |
| |
| |
| TRectD rectOut(tile.m_pos, TDimensionD(tile.getRaster()->getLx(), |
| tile.getRaster()->getLy())); |
| |
| |
| |
| |
| TRectD bboxIn; |
| if (!m_up->getBBox(frame, bboxIn, info) || rectOut.isEmpty()) return; |
| |
| TRectD rectIn(rectOut); |
| enlarge(bboxIn, rectIn, blurI); |
| |
| if (rectIn.isEmpty()) return; |
| |
| |
| TTile tileIn; |
| m_up->allocateAndCompute(tileIn, rectIn.getP00(), |
| TDimension(rectIn.getLx(), rectIn.getLy()), |
| tile.getRaster(), frame, info); |
| |
| TTile tileRef; |
| m_ref->allocateAndCompute(tileRef, rectIn.getP00(), |
| TDimension(rectIn.getLx(), rectIn.getLy()), |
| tile.getRaster(), frame, info); |
| |
| |
| TRasterP inRas(tileIn.getRaster()); |
| TRasterP refRas(tileRef.getRaster()); |
| TRasterP outRas(tile.getRaster()); |
| |
| TRaster32P in32(inRas); |
| TRaster32P ref32(refRas); |
| TRaster32P out32(outRas); |
| |
| TPoint displacement(convert( |
| rectIn.getP00() - tile.m_pos)); |
| |
| |
| if (in32 && ref32 && out32) |
| doLocalBlur<TPixelRGBM32, TPixelGR8>(in32, ref32, out32, blur, |
| displacement); |
| else { |
| TRaster64P in64(inRas); |
| TRaster64P ref64(refRas); |
| TRaster64P out64(outRas); |
| |
| if (in64 && ref64 && out64) |
| doLocalBlur<TPixelRGBM64, TPixelGR16>(in64, ref64, out64, blur, |
| displacement); |
| else |
| throw TException("LocalBlurFx: unsupported raster type"); |
| } |
| } |
| |
| |
| |
| int LocalBlurFx::getMemoryRequirement(const TRectD &rect, double frame, |
| const TRenderSettings &info) { |
| double blur = |
| fabs(m_value->getValue(frame) * sqrt(fabs(info.m_affine.det()))); |
| int blurI = tceil(blur); |
| |
| return 2 * TRasterFx::memorySize(rect.enlarge(blurI), info.m_bpp); |
| } |
| |
| |
| |
| FX_PLUGIN_IDENTIFIER(LocalBlurFx, "localBlurFx") |
| |