tahoma2d/toonz/sources/include/tcg/hpp/image_ops.hpp

314 lines
10 KiB
C++
Raw Normal View History

2016-05-17 03:04:11 +12:00
#pragma once
2016-03-19 06:57:51 +13:00
#ifndef TCG_IMAGE_OPS_HPP
#define TCG_IMAGE_OPS_HPP
// tcg includes
#include "../image_ops.h"
#include "../pixel.h"
// STD includes
#include <assert.h>
#include <memory>
2016-06-15 18:43:10 +12:00
namespace tcg {
namespace image_ops {
2016-03-19 06:57:51 +13:00
//**************************************************************************
// Flat Blur implementation
//**************************************************************************
template <typename PtrIn, typename PtrOut, typename PixSum>
void _flatFilterLine(PtrIn in, PtrOut out, int lx, int addIn, int addOut,
2016-06-15 18:43:10 +12:00
int radius, PixSum *sums) {
typedef typename std::iterator_traits<PtrIn> trIn;
typedef typename trIn::value_type pixIn_type;
struct locals {
inline static void fillSums(int lx, int radius, PtrIn lineIn,
PixSum *pixsum, int addIn, int addSum) {
using namespace pixel_ops;
PtrIn newPixIn = lineIn;
PixSum sum;
// Build up to radius pixels adding new pixels only
int x, xNew, xEnd = tmin(radius, lx);
for (xNew = 0; xNew != xEnd; ++xNew, newPixIn += addIn)
sum = sum + *newPixIn;
// Store sums AND add new pixels. Observe that the current pixel value is
// decreased
// BEFORE storage. This makes this function "strict" in calculating the
// sums.
for (x = 0; xNew != lx;
++x, ++xNew, lineIn += addIn, newPixIn += addIn, pixsum += addSum) {
sum = (sum + *newPixIn) - *lineIn;
*pixsum = *pixsum + sum;
}
// Finally, without adding new pixels
for (; x != lx; ++x, lineIn += addIn, pixsum += addSum) {
sum = sum - *lineIn;
*pixsum = *pixsum + sum;
}
}
};
memset(sums, 0, lx * sizeof(PixSum));
// Add *strict* halves of the convolution sums
locals::fillSums(lx, radius, in, sums, addIn,
1); // Right part of the convolution
locals::fillSums(lx, radius, in + addIn * (lx - 1), sums + lx - 1, -addIn,
-1); // Left ...
// Normalize sums
int diameter = 2 * radius + 1;
for (int x = 0; x != lx; ++x, in += addIn, out += addOut, ++sums) {
using namespace pixel_ops;
pixIn_type pix(*in);
pixel_ops::assign(
pix, (*sums + pix) / diameter); // Note that *in is added, due *strict*
// halving the sums above
*out = pix;
}
2016-03-19 06:57:51 +13:00
}
//----------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
template <typename PtrIn, typename PtrOut, typename PixSum,
typename SelectorFunc>
2016-03-19 06:57:51 +13:00
void _flatFilterLine(PtrIn in, PtrOut out, int lx, int addIn, int addOut,
2016-06-15 18:43:10 +12:00
SelectorFunc selector, int radius, PixSum *sums,
int *counts) {
typedef typename std::iterator_traits<PtrIn> trIn;
typedef typename trIn::value_type pixIn_type;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
struct locals {
inline static void fillSums(int lx, int radius, PtrIn lineIn,
PixSum *pixsum, int *pixcount, int addIn,
int addSum, SelectorFunc selector) {
using namespace pixel_ops;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
PtrIn newPixIn = lineIn;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
PixSum sum;
int count = 0;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
// Build up to radius pixels adding new pixels only
int x, xNew, xEnd = tmin(radius, lx);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
for (xNew = 0; xNew != xEnd; ++xNew, newPixIn += addIn) {
const pixIn_type &npi = *newPixIn;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
if (selector(npi)) sum = sum + npi, ++count;
}
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
// Store sums AND add new pixels. Observe that the current pixel value is
// decreased
// BEFORE storage. This makes this function "strict" in calculating the
// sums.
for (x = 0; xNew != lx; ++x, ++xNew, lineIn += addIn, newPixIn += addIn,
pixsum += addSum, pixcount += addSum) {
const pixIn_type &npi = *newPixIn, &li = *lineIn;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
if (selector(npi)) sum = sum + npi, ++count;
if (selector(li)) sum = sum - li, --count;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
*pixsum = *pixsum + sum, *pixcount += count;
}
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
// Finally, without adding new pixels
for (; x != lx;
++x, lineIn += addIn, pixsum += addSum, pixcount += addSum) {
const pixIn_type &li = *lineIn;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
if (selector(li)) sum = sum - li, --count;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
*pixsum = *pixsum + sum, *pixcount += count;
}
}
};
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
memset(sums, 0, lx * sizeof(PixSum));
memset(counts, 0, lx * sizeof(int));
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
// Add *strict* halves of the convolution sums
locals::fillSums(lx, radius, in, sums, counts, addIn, 1, selector);
locals::fillSums(lx, radius, in + addIn * (lx - 1), sums + lx - 1,
counts + lx - 1, -addIn, -1, selector);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
// Normalize sums
for (int x = 0; x != lx; ++x, in += addIn, out += addOut, ++sums, ++counts) {
using namespace pixel_ops;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
assert(*counts >= 0);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
pixIn_type pix(*in);
pixel_ops::assign(pix, (*sums + pix) / (*counts + 1));
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
*out = pix;
}
2016-03-19 06:57:51 +13:00
}
//----------------------------------------------------------------------
template <typename ImgIn, typename ImgOut, typename Scalar>
2016-06-15 18:43:10 +12:00
void blurRows(const ImgIn &imgIn, ImgOut &imgOut, int radius, Scalar) {
typedef typename image_traits<ImgIn>::pixel_ptr_type PtrIn;
typedef typename image_traits<ImgOut>::pixel_ptr_type PtrOut;
typedef tcg::Pixel<Scalar, image_traits<ImgIn>::pixel_category> PixSum;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
// Validate parameters
int inLx = image_traits<ImgIn>::width(imgIn),
inLy = image_traits<ImgIn>::height(imgIn);
int outLx = image_traits<ImgOut>::width(imgOut),
outLy = image_traits<ImgOut>::height(imgOut);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
assert(inLx == outLx && inLy == outLy);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
int inWrap = image_traits<ImgIn>::wrap(imgIn),
outWrap = image_traits<ImgOut>::wrap(imgOut);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
// Allocate an intermediate line of pixels to store sum values
std::unique_ptr<PixSum[]> sums(new PixSum[inLx]);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
// Filter rows
for (int y = 0; y != inLy; ++y) {
PtrIn lineIn = image_traits<ImgIn>::pixel(imgIn, 0, y);
PtrOut lineOut = image_traits<ImgOut>::pixel(imgOut, 0, y);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
_flatFilterLine(lineIn, lineOut, inLx, 1, 1, radius, sums.get());
}
2016-03-19 06:57:51 +13:00
}
//----------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
template <typename ImgIn, typename ImgOut, typename SelectorFunc,
typename Scalar>
void blurRows(const ImgIn &imgIn, ImgOut &imgOut, int radius,
SelectorFunc selector, Scalar) {
typedef typename image_traits<ImgIn>::pixel_ptr_type PtrIn;
typedef typename image_traits<ImgOut>::pixel_ptr_type PtrOut;
typedef tcg::Pixel<Scalar, image_traits<ImgIn>::pixel_category> PixSum;
// Validate parameters
int inLx = image_traits<ImgIn>::width(imgIn),
inLy = image_traits<ImgIn>::height(imgIn);
int outLx = image_traits<ImgOut>::width(imgOut),
outLy = image_traits<ImgOut>::height(imgOut);
assert(inLx == outLx && inLy == outLy);
int inWrap = image_traits<ImgIn>::wrap(imgIn),
outWrap = image_traits<ImgOut>::wrap(imgOut);
// Allocate an intermediate line of pixels to store sum values
std::unique_ptr<PixSum[]> sums(new PixSum[inLx]);
std::unique_ptr<int[]> counts(new int[inLx]);
2016-06-15 18:43:10 +12:00
// Filter rows
for (int y = 0; y != inLy; ++y) {
PtrIn lineIn = image_traits<ImgIn>::pixel(imgIn, 0, y);
PtrOut lineOut = image_traits<ImgOut>::pixel(imgOut, 0, y);
_flatFilterLine(lineIn, lineOut, inLx, 1, 1, selector, radius, sums.get(),
counts.get());
}
2016-03-19 06:57:51 +13:00
}
//----------------------------------------------------------------------
template <typename ImgIn, typename ImgOut, typename Scalar>
2016-06-15 18:43:10 +12:00
void blurCols(const ImgIn &imgIn, ImgOut &imgOut, int radius, Scalar) {
typedef typename image_traits<ImgIn>::pixel_ptr_type PtrIn;
typedef typename image_traits<ImgOut>::pixel_ptr_type PtrOut;
typedef tcg::Pixel<Scalar, typename image_traits<ImgIn>::pixel_category>
PixSum;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
// Validate parameters
int inLx = image_traits<ImgIn>::width(imgIn),
inLy = image_traits<ImgIn>::height(imgIn);
int outLx = image_traits<ImgOut>::width(imgOut),
outLy = image_traits<ImgOut>::height(imgOut);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
assert(inLx == outLx && inLy == outLy);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
int inWrap = image_traits<ImgIn>::wrap(imgIn),
outWrap = image_traits<ImgOut>::wrap(imgOut);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
// Allocate an intermediate line of pixels to store sum values
std::unique_ptr<PixSum[]> sums(new PixSum[inLy]);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
// Filter columns
for (int x = 0; x != inLx; ++x) {
PtrIn lineIn = image_traits<ImgIn>::pixel(imgIn, x, 0);
PtrOut lineOut = image_traits<ImgOut>::pixel(imgOut, x, 0);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
_flatFilterLine(lineIn, lineOut, inLy, inWrap, outWrap, radius, sums.get());
}
2016-03-19 06:57:51 +13:00
}
//----------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
template <typename ImgIn, typename ImgOut, typename SelectorFunc,
typename Scalar>
void blurCols(const ImgIn &imgIn, ImgOut &imgOut, int radius,
SelectorFunc selector, Scalar) {
typedef typename image_traits<ImgIn>::pixel_ptr_type PtrIn;
typedef typename image_traits<ImgOut>::pixel_ptr_type PtrOut;
typedef tcg::Pixel<Scalar, typename image_traits<ImgIn>::pixel_category>
PixSum;
// Validate parameters
int inLx = image_traits<ImgIn>::width(imgIn),
inLy = image_traits<ImgIn>::height(imgIn);
int outLx = image_traits<ImgOut>::width(imgOut),
outLy = image_traits<ImgOut>::height(imgOut);
assert(inLx == outLx && inLy == outLy);
int inWrap = image_traits<ImgIn>::wrap(imgIn),
outWrap = image_traits<ImgOut>::wrap(imgOut);
// Allocate an intermediate line of pixels to store sum values
std::unique_ptr<PixSum[]> sums(new PixSum[inLy]);
std::unique_ptr<int[]> counts(new int[inLy]);
2016-06-15 18:43:10 +12:00
// Filter columns
for (int x = 0; x != inLx; ++x) {
PtrIn lineIn = image_traits<ImgIn>::pixel(imgIn, x, 0);
PtrOut lineOut = image_traits<ImgOut>::pixel(imgOut, x, 0);
_flatFilterLine(lineIn, lineOut, inLy, inWrap, outWrap, selector, radius,
sums.get(), counts.get());
}
2016-03-19 06:57:51 +13:00
}
//----------------------------------------------------------------------
template <typename ImgIn, typename ImgOut, typename Scalar>
2016-06-15 18:43:10 +12:00
void blur(const ImgIn &imgIn, ImgOut &imgOut, int radius, Scalar) {
blurRows(imgIn, imgOut, radius, Scalar);
blurCols(imgOut, imgOut, radius, Scalar);
2016-03-19 06:57:51 +13:00
}
//----------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
template <typename ImgIn, typename ImgOut, typename SelectorFunc,
typename Scalar>
void blur(const ImgIn &imgIn, ImgOut &imgOut, int radius, SelectorFunc selector,
Scalar) {
blurRows(imgIn, imgOut, radius, selector, Scalar);
blurCols(imgOut, imgOut, radius, selector, Scalar);
2016-03-19 06:57:51 +13:00
}
}
2016-06-15 18:43:10 +12:00
} // namespace tcg::image_ops
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
#endif // TCG_IMAGE_OPS_HPP