| #include <vector> // std::vector |
| #include <cmath> // cos(),sin(),sqrt() |
| #include <limits> // std::numeric_limits<T> |
| #include <stdexcept> // std::domain_error() |
| #include "igs_ifx_common.h" |
| #include "igs_radial_blur.h" |
| namespace |
| { |
| |
| template <class T> |
| class radial_ |
| { |
| public: |
| radial_( |
| const T *in_top, const int height, const int width, const int channels, const double xc, const double yc, const double sub_size, const int imax, const double dmax, const double intensity |
| , |
| const double radius |
| ) |
| : in_top_(in_top), hh_(height), ww_(width), cc_(channels), xc_(xc), yc_(yc), sub_size_(sub_size), imax_(imax), dmax_(dmax), intensity_(intensity), radius_(radius) |
| { |
| } |
| void pixel_value( |
| const T *in_current_pixel, const int xx, const int yy, const int z1, const int z2, const double ref_increase_val, const double ref_decrease_val, const double each_pixel_blur_ratio, T *result_pixel) |
| { |
| |
| const double xp = static_cast<double>(xx) + 0.5; |
| const double yp = static_cast<double>(yy) + 0.5; |
| |
| |
| const double xv = xp - this->xc_; |
| const double yv = yp - this->yc_; |
| const double dist = sqrt(xv * xv + yv * yv); |
| |
| |
| if (dist <= this->radius_) { |
| for (int zz = z1; zz <= z2; ++zz) { |
| result_pixel[zz] = in_current_pixel[zz]; |
| } |
| return; |
| } |
| |
| |
| const double cosval = xv / dist; |
| const double sinval = yv / dist; |
| |
| |
| double scale = this->intensity_; |
| if (0.0 <= each_pixel_blur_ratio) { |
| scale *= each_pixel_blur_ratio; |
| } |
| const double length = (dist - this->radius_) * |
| scale; |
| const double count_half = floor( |
| length / 2.0 / this->sub_size_); |
| const double sub_sta = -this->sub_size_ * count_half; |
| const double sub_end = this->sub_size_ * count_half; |
| |
| |
| std::vector<double> accum_val(this->cc_); |
| int accum_counter = 0; |
| |
| |
| for (double ss = this->sub_size_ / 2.0 - 0.5; |
| ss < 0.5; ss += this->sub_size_) { |
| |
| |
| const double xps = xp + ss * sinval; |
| const double yps = yp + ss * cosval; |
| |
| |
| const double xvs = xps - this->xc_; |
| const double yvs = yps - this->yc_; |
| const double dists = sqrt(xvs * xvs + yvs * yvs); |
| |
| |
| const double cosvals = xvs / dists; |
| const double sinvals = yvs / dists; |
| |
| |
| for (double tt = sub_sta; |
| tt <= sub_end; tt += this->sub_size_) { |
| |
| int xi = static_cast<int>(xps + tt * cosvals); |
| int yi = static_cast<int>(yps + tt * sinvals); |
| |
| |
| xi = (xi < 0) ? 0 : ((this->ww_ <= xi) ? this->ww_ - 1 : xi); |
| yi = (yi < 0) ? 0 : ((this->hh_ <= yi) ? this->hh_ - 1 : yi); |
| |
| |
| const T *in_current = this->in_top_ + |
| this->cc_ * this->ww_ * yi + |
| this->cc_ * xi; |
| |
| |
| for (int zz = z1; zz <= z2; ++zz) { |
| accum_val[zz] += |
| static_cast<double>(in_current[zz]); |
| } |
| ++accum_counter; |
| } |
| } |
| |
| if (accum_counter <= 0) { |
| for (int zz = z1; zz <= z2; ++zz) { |
| result_pixel[zz] = in_current_pixel[zz]; |
| } |
| return; |
| } |
| |
| for (int zz = z1; zz <= z2; ++zz) { |
| accum_val[zz] /= static_cast<double>(accum_counter); |
| |
| if ((0 <= ref_increase_val) && |
| (in_current_pixel[zz] < accum_val[zz])) { |
| |
| accum_val[zz] = |
| static_cast<double>(in_current_pixel[zz]) + |
| (accum_val[zz] - in_current_pixel[zz]) * |
| ref_increase_val; |
| } else if ((0 <= ref_decrease_val) && |
| (accum_val[zz] < in_current_pixel[zz])) { |
| |
| accum_val[zz] = |
| static_cast<double>(in_current_pixel[zz]) + |
| (accum_val[zz] - in_current_pixel[zz]) * |
| ref_decrease_val; |
| } |
| |
| accum_val[zz] += 0.5; |
| if (this->dmax_ < accum_val[zz]) { |
| result_pixel[zz] = static_cast<T>(this->imax_); |
| } else if (accum_val[zz] < 0) { |
| result_pixel[zz] = 0; |
| } else { |
| result_pixel[zz] = static_cast<T>(accum_val[zz]); |
| } |
| } |
| } |
| |
| private: |
| radial_() {} |
| |
| const T *in_top_; |
| const int hh_; |
| const int ww_; |
| const int cc_; |
| const double xc_; |
| const double yc_; |
| const double sub_size_; |
| const int imax_; |
| const double dmax_; |
| const double intensity_; |
| const double radius_; |
| |
| |
| radial_(const radial_ &); |
| |
| |
| radial_ &operator=(const radial_ &); |
| }; |
| template <class IT, class RT> |
| void radial_convert_template_( |
| const IT *in, const int margin /* 参照画像(in)がもつ余白 */ |
| |
| , |
| const RT *ref /* 求める画像(out)と同じ高さ、幅、チャンネル数 */ |
| , |
| const int ref_bits, const int ref_mode // R,G,B,A,luminance |
| |
| , |
| IT *out, const int hh /* 求める画像(out)の高さ */ |
| , |
| const int ww /* 求める画像(out)の幅 */ |
| , |
| const int cc, const double xc, const double yc, const double intensity /* 強度。ゼロより大きく2以下 */ |
| /* radius円境界での平均値ぼかしゼロとするためintensityは2より小さい */ |
| , |
| const double radius /* 平均値ぼかしの始まる半径 */ |
| , |
| const int sub_div /* 1ならJaggy、2以上はAntialias */ |
| , |
| const bool alpha_rendering_sw) |
| { |
| ref_bits; |
| |
| |
| if (intensity <= 0.0 || sub_div <= 0) { |
| return; |
| } |
| |
| radial_<IT> cl_ra( |
| in, hh + margin * 2, ww + margin * 2, cc, xc + margin, yc + margin, 1.0 / sub_div, std::numeric_limits<IT>::max() |
| , |
| static_cast<double>(std::numeric_limits<IT>::max()), intensity, radius); |
| |
| #if defined RGBA_ORDER_OF_TOONZ6 |
| const int z1 = igs::image::rgba::blu; |
| const int z2 = igs::image::rgba::red; |
| #elif defined RGBA_ORDER_OF_OPENGL |
| const int z1 = igs::image::rgba::red; |
| const int z2 = igs::image::rgba::blu; |
| #else |
| Must be define / DRGBA_ORDER_OF_TOONZ6 or / DRGBA_ORDER_OF_OPENGL |
| #endif |
| const IT *p_in = in + margin * (ww + margin * 2) * cc + margin * cc; |
| IT *pout = out; |
| |
| if (0 == ref) { |
| if (igs::image::rgba::siz == cc) { |
| using namespace igs::image::rgba; |
| if (alpha_rendering_sw) { |
| for (int yy = margin; yy < hh + margin; ++yy, p_in += 2 * margin * cc) { |
| for (int xx = margin; xx < ww + margin; ++xx, p_in += cc, pout += cc) { |
| cl_ra.pixel_value(p_in, xx, yy, alp, alp, -1.0, -1.0, -1.0, pout); |
| if (0 == pout[alp]) { |
| pout[red] = p_in[red]; |
| pout[gre] = p_in[gre]; |
| pout[blu] = p_in[blu]; |
| continue; |
| } |
| cl_ra.pixel_value(p_in, xx, yy, z1, z2, -1.0, -1.0, -1.0, pout); |
| } |
| } |
| } else { |
| const unsigned int val_max = std::numeric_limits<IT>::max(); |
| for (int yy = margin; yy < hh + margin; ++yy, p_in += 2 * margin * cc) { |
| for (int xx = margin; xx < ww + margin; ++xx, p_in += cc, pout += cc) { |
| pout[alp] = p_in[alp]; |
| if (0 == pout[alp]) { |
| pout[red] = p_in[red]; |
| pout[gre] = p_in[gre]; |
| pout[blu] = p_in[blu]; |
| continue; |
| } |
| |
| cl_ra.pixel_value( |
| p_in, xx, yy, z1, z2, static_cast<double>(p_in[alp]) / val_max, -1.0, -1.0, pout); |
| } |
| } |
| } |
| } else { |
| for (int yy = margin; yy < hh + margin; ++yy, p_in += 2 * margin * cc) { |
| for (int xx = margin; xx < ww + margin; ++xx, p_in += cc, pout += cc) { |
| cl_ra.pixel_value(p_in, xx, yy, 0, cc - 1, -1.0, -1.0, -1.0, pout); |
| } |
| } |
| } |
| } else { |
| const RT *refe = ref; |
| const int r_max = std::numeric_limits<RT>::max(); |
| if (igs::image::rgba::siz == cc) { |
| using namespace igs::image::rgba; |
| if (alpha_rendering_sw) { |
| for (int yy = margin; yy < hh + margin; ++yy, p_in += 2 * margin * cc) { |
| for (int xx = margin; xx < ww + margin; ++xx, p_in += cc, pout += cc, refe += cc) { |
| const double refv = igs::color::ref_value( |
| refe, cc, r_max, ref_mode); |
| if (0 == refv) { |
| for (int zz = 0; zz < cc; ++zz) { |
| pout[zz] = p_in[zz]; |
| } |
| continue; |
| } |
| |
| cl_ra.pixel_value(p_in, xx, yy, alp, alp, -1.0, -1.0, refv, pout); |
| if (0 == pout[alp]) { |
| pout[red] = p_in[red]; |
| pout[gre] = p_in[gre]; |
| pout[blu] = p_in[blu]; |
| continue; |
| } |
| cl_ra.pixel_value(p_in, xx, yy, z1, z2, -1.0, -1.0, refv, pout); |
| } |
| } |
| } else { |
| const unsigned int val_max = std::numeric_limits<IT>::max(); |
| for (int yy = margin; yy < hh + margin; ++yy, p_in += 2 * margin * cc) { |
| for (int xx = margin; xx < ww + margin; ++xx, p_in += cc, pout += cc, refe += cc) { |
| const double refv = igs::color::ref_value( |
| refe, cc, r_max, ref_mode); |
| if (0 == refv) { |
| for (int zz = 0; zz < cc; ++zz) { |
| pout[zz] = p_in[zz]; |
| } |
| continue; |
| } |
| |
| pout[alp] = p_in[alp]; |
| if (0 == pout[alp]) { |
| pout[red] = p_in[red]; |
| pout[gre] = p_in[gre]; |
| pout[blu] = p_in[blu]; |
| continue; |
| } |
| cl_ra.pixel_value(p_in, xx, yy, z1, z2, static_cast<double>(p_in[alp]) / val_max, -1.0, refv, pout); |
| } |
| } |
| } |
| } else { |
| for (int yy = margin; yy < hh + margin; ++yy, p_in += 2 * margin * cc) { |
| for (int xx = margin; xx < ww + margin; ++xx, p_in += cc, pout += cc, refe += cc) { |
| const double refv = igs::color::ref_value( |
| refe, cc, r_max, ref_mode); |
| if (0 == refv) { |
| for (int zz = 0; zz < cc; ++zz) { |
| pout[zz] = p_in[zz]; |
| } |
| continue; |
| } |
| |
| cl_ra.pixel_value(p_in, xx, yy, 0, cc - 1, -1.0, -1.0, refv, pout); |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| namespace |
| { |
| class twist_ |
| { |
| public: |
| twist_( |
| const int height, const double xc, const double yc, const double twist_radian, const double twist_radius) |
| : xc_(xc), yc_(yc), twist_xp_(0), twist_yp_(0), twist_radian_(twist_radian), twist_radius_(twist_radius), current_xp_(0), current_yp_(0), current_radian_(0), current_cos_(0), current_sin_(0), current_radius_(0) |
| { |
| |
| |
| if (this->twist_radius_ <= 0.0) { |
| this->twist_radius_ = height / 2.0; |
| } |
| |
| if (this->twist_radius_ <= 0.0) { |
| throw std::domain_error( |
| "twist_radius is equal less than zero"); |
| } |
| } |
| void current_pos(const double xp, const double yp) |
| { |
| |
| this->current_xp_ = xp; |
| this->current_yp_ = yp; |
| |
| |
| const double xv = xp - this->xc_; |
| const double yv = yp - this->yc_; |
| this->current_radius_ = sqrt(xv * xv + yv * yv); |
| |
| |
| const double tt = this->current_radius_ / this->twist_radius_; |
| |
| |
| const double xx = tt * cos(tt * this->twist_radian_); |
| const double yy = tt * sin(tt * this->twist_radian_); |
| |
| |
| this->current_radian_ = atan2(yv, xv) - atan2(yy, xx); |
| |
| |
| this->current_cos_ = cos(this->current_radian_); |
| this->current_sin_ = sin(this->current_radian_); |
| this->twist_xp_ = xx * this->current_cos_ - |
| yy * this->current_sin_; |
| this->twist_yp_ = xx * this->current_sin_ + |
| yy * this->current_cos_; |
| } |
| void twist_pos( |
| const double pixel_pos, int &xi, int &yi) |
| { |
| |
| const double tt = (this->current_radius_ + pixel_pos) / |
| this->twist_radius_; |
| |
| |
| const double xx = tt * cos(tt * this->twist_radian_); |
| const double yy = tt * sin(tt * this->twist_radian_); |
| |
| |
| double x2 = xx * this->current_cos_ - |
| yy * this->current_sin_; |
| double y2 = xx * this->current_sin_ + |
| yy * this->current_cos_; |
| |
| |
| x2 = (x2 - this->twist_xp_); |
| y2 = (y2 - this->twist_yp_); |
| |
| |
| x2 *= this->twist_radius_; |
| y2 *= this->twist_radius_; |
| |
| |
| x2 += this->current_xp_; |
| y2 += this->current_yp_; |
| |
| xi = static_cast<int>(x2); |
| yi = static_cast<int>(y2); |
| } |
| |
| private: |
| twist_(); |
| |
| const double xc_; |
| const double yc_; |
| |
| double twist_xp_; |
| double twist_yp_; |
| double twist_radian_; |
| double twist_radius_; |
| |
| double current_xp_; |
| double current_yp_; |
| double current_radian_; |
| double current_cos_; |
| double current_sin_; |
| double current_radius_; |
| |
| |
| twist_(const twist_ &); |
| |
| |
| twist_ &operator=(const twist_ &); |
| }; |
| |
| template <class T> |
| class radial_twist_ |
| { |
| public: |
| radial_twist_( |
| const T *in_top, const int height |
| , |
| const int width |
| , |
| const int channels, const double xc, const double yc, const double sub_size, const int imax, const double dmax, const double intensity |
| , |
| const double radius |
| , |
| const double twist_radian, const double twist_radius) |
| : in_top_(in_top), hh_(height), ww_(width), cc_(channels), xc_(xc), yc_(yc), sub_size_(sub_size), imax_(imax), dmax_(dmax), intensity_(intensity), radius_(radius), cl_tw_( |
| height, xc, yc, twist_radian, twist_radius) |
| { |
| } |
| void pixel_value( |
| const T *in_current_pixel, const int xx, const int yy, const int z1, const int z2, const double ref_increase_val, const double ref_decrease_val, const double each_pixel_blur_ratio, T *result_pixel) |
| { |
| |
| const double xp = static_cast<double>(xx) + 0.5; |
| const double yp = static_cast<double>(yy) + 0.5; |
| |
| |
| const double xv = xp - this->xc_; |
| const double yv = yp - this->yc_; |
| const double dist = sqrt(xv * xv + yv * yv); |
| |
| |
| if (dist <= this->radius_) { |
| for (int zz = z1; zz <= z2; ++zz) { |
| result_pixel[zz] = in_current_pixel[zz]; |
| } |
| return; |
| } |
| |
| |
| double scale = this->intensity_; |
| if (0.0 <= each_pixel_blur_ratio) { |
| scale *= each_pixel_blur_ratio; |
| } |
| const double length = (dist - this->radius_) * |
| scale; |
| const double count_half = floor(length / 2.0 / this->sub_size_); |
| const double sub_sta = -this->sub_size_ * count_half; |
| const double sub_end = this->sub_size_ * count_half; |
| |
| |
| std::vector<double> accum_val(this->cc_); |
| int accum_counter = 0; |
| |
| |
| for (double xsub = this->sub_size_ / 2.0 - 0.5; |
| xsub < 0.5; xsub += this->sub_size_) { |
| for (double ysub = this->sub_size_ / 2.0 - 0.5; |
| ysub < 0.5; ysub += this->sub_size_) { |
| |
| |
| this->cl_tw_.current_pos(xp + xsub, yp + ysub); |
| |
| |
| for (double tt = sub_sta; tt <= sub_end; tt += this->sub_size_) { |
| |
| int xi = 0; |
| int yi = 0; |
| this->cl_tw_.twist_pos(tt, xi, yi); |
| |
| |
| xi = (xi < 0) ? 0 : ((this->ww_ <= xi) ? this->ww_ - 1 : xi); |
| yi = (yi < 0) ? 0 : ((this->hh_ <= yi) ? this->hh_ - 1 : yi); |
| |
| |
| const T *in_current = this->in_top_ + |
| this->cc_ * this->ww_ * yi + |
| this->cc_ * xi; |
| |
| |
| for (int zz = z1; zz <= z2; ++zz) { |
| accum_val[zz] += |
| static_cast<double>(in_current[zz]); |
| } |
| ++accum_counter; |
| } |
| } |
| } |
| |
| if (accum_counter <= 0) { |
| for (int zz = z1; zz <= z2; ++zz) { |
| result_pixel[zz] = in_current_pixel[zz]; |
| } |
| return; |
| } |
| |
| for (int zz = z1; zz <= z2; ++zz) { |
| accum_val[zz] /= static_cast<double>(accum_counter); |
| |
| if ((0 <= ref_increase_val) && |
| (in_current_pixel[zz] < accum_val[zz])) { |
| |
| accum_val[zz] = |
| static_cast<double>(in_current_pixel[zz]) + |
| (accum_val[zz] - in_current_pixel[zz]) * |
| ref_increase_val; |
| } else if ((0 <= ref_decrease_val) && |
| (accum_val[zz] < in_current_pixel[zz])) { |
| |
| accum_val[zz] = |
| static_cast<double>(in_current_pixel[zz]) + |
| (accum_val[zz] - in_current_pixel[zz]) * |
| ref_decrease_val; |
| } |
| |
| accum_val[zz] += 0.5; |
| if (this->dmax_ < accum_val[zz]) { |
| result_pixel[zz] = static_cast<T>(this->imax_); |
| } else if (accum_val[zz] < 0) { |
| result_pixel[zz] = 0; |
| } else { |
| result_pixel[zz] = static_cast<T>( |
| accum_val[zz]); |
| } |
| } |
| } |
| |
| private: |
| radial_twist_() {} |
| |
| const T *in_top_; |
| const int hh_; |
| const int ww_; |
| const int cc_; |
| const double xc_; |
| const double yc_; |
| const double sub_size_; |
| const int imax_; |
| const double dmax_; |
| const double intensity_; |
| const double radius_; |
| twist_ cl_tw_; |
| |
| |
| radial_twist_(const radial_twist_ &); |
| |
| |
| radial_twist_ &operator=(const radial_twist_ &); |
| }; |
| |
| template <class IT, class RT> |
| void twist_convert_template_( |
| const IT *in, const int margin /* 参照画像(in)がもつ余白 */ |
| |
| , |
| const RT *ref /* 求める画像(out)と同じ高さ、幅、チャンネル数 */ |
| , |
| const int ref_bits, const int ref_mode // R,G,B,A,luminance |
| |
| , |
| IT *out, const int hh /* 求める画像(out)の高さ */ |
| , |
| const int ww /* 求める画像(out)の幅 */ |
| , |
| const int cc, const double xc, const double yc, const double twist_radian, const double twist_radius, const double intensity /* 強度。ゼロより大きく2以下 */ |
| /* radius円境界での平均値ぼかしゼロとするためintensityは2より小さい */ |
| , |
| const double radius /* 平均値ぼかしの始まる半径 */ |
| , |
| const int sub_div /* 1ならJaggy、2以上はAntialias */ |
| , |
| const bool alpha_rendering_sw) |
| { |
| ref_bits; |
| |
| |
| if (intensity <= 0.0 || sub_div <= 0) { |
| return; |
| } |
| |
| radial_twist_<IT> cl_ratw( |
| in, hh + margin * 2, ww + margin * 2, cc, xc + margin, yc + margin, 1.0 / sub_div, std::numeric_limits<IT>::max(), static_cast<double>(std::numeric_limits<IT>::max()), intensity, radius, twist_radian, twist_radius); |
| |
| #if defined RGBA_ORDER_OF_TOONZ6 |
| const int z1 = igs::image::rgba::blu; |
| const int z2 = igs::image::rgba::red; |
| #elif defined RGBA_ORDER_OF_OPENGL |
| const int z1 = igs::image::rgba::red; |
| const int z2 = igs::image::rgba::blu; |
| #else |
| Must be define / DRGBA_ORDER_OF_TOONZ6 or / DRGBA_ORDER_OF_OPENGL |
| #endif |
| |
| const IT *p_in = in + margin * (ww + margin * 2) * cc + margin * cc; |
| IT *pout = out; |
| |
| if (0 == ref) { |
| if (igs::image::rgba::siz == cc) { |
| using namespace igs::image::rgba; |
| if (alpha_rendering_sw) { |
| for (int yy = margin; yy < hh + margin; ++yy, p_in += 2 * margin * cc) { |
| for (int xx = margin; xx < ww + margin; ++xx, p_in += cc, pout += cc) { |
| cl_ratw.pixel_value(p_in, xx, yy, alp, alp, -1.0, -1.0, -1.0, pout); |
| if (0 == pout[alp]) { |
| pout[red] = p_in[red]; |
| pout[gre] = p_in[gre]; |
| pout[blu] = p_in[blu]; |
| continue; |
| } |
| cl_ratw.pixel_value(p_in, xx, yy, z1, z2, -1.0, -1.0, -1.0, pout); |
| } |
| } |
| } else { |
| const unsigned int val_max = std::numeric_limits<IT>::max(); |
| for (int yy = margin; yy < hh + margin; ++yy, p_in += 2 * margin * cc) { |
| for (int xx = margin; xx < ww + margin; ++xx, p_in += cc, pout += cc) { |
| pout[alp] = p_in[alp]; |
| if (0 == pout[alp]) { |
| pout[red] = p_in[red]; |
| pout[gre] = p_in[gre]; |
| pout[blu] = p_in[blu]; |
| continue; |
| } |
| cl_ratw.pixel_value( |
| p_in, xx, yy, z1, z2, static_cast<double>(p_in[alp]) / val_max, -1.0, -1.0, pout); |
| } |
| } |
| } |
| } else { |
| for (int yy = margin; yy < hh + margin; ++yy, p_in += 2 * margin * cc) { |
| for (int xx = margin; xx < ww + margin; ++xx, p_in += cc, pout += cc) { |
| cl_ratw.pixel_value(p_in, xx, yy, 0, cc - 1, -1.0, -1.0, -1.0, pout); |
| } |
| } |
| } |
| } else { |
| const RT *refe = ref; |
| const int r_max = std::numeric_limits<RT>::max(); |
| if (igs::image::rgba::siz == cc) { |
| using namespace igs::image::rgba; |
| if (alpha_rendering_sw) { |
| for (int yy = margin; yy < hh + margin; ++yy, p_in += 2 * margin * cc) { |
| for (int xx = margin; xx < ww + margin; ++xx, p_in += cc, pout += cc, refe += cc) { |
| const double refv = igs::color::ref_value( |
| refe, cc, r_max, ref_mode); |
| if (0 == refv) { |
| for (int zz = 0; zz < cc; ++zz) { |
| pout[zz] = p_in[zz]; |
| } |
| continue; |
| } |
| |
| cl_ratw.pixel_value(p_in, xx, yy, alp, alp, -1.0, -1.0, refv, pout); |
| if (0 == pout[alp]) { |
| pout[red] = p_in[red]; |
| pout[gre] = p_in[gre]; |
| pout[blu] = p_in[blu]; |
| continue; |
| } |
| cl_ratw.pixel_value(p_in, xx, yy, z1, z2, -1.0, -1.0, refv, pout); |
| } |
| } |
| } else { |
| const unsigned int val_max = std::numeric_limits<IT>::max(); |
| for (int yy = margin; yy < hh + margin; ++yy, p_in += 2 * margin * cc) { |
| for (int xx = margin; xx < ww + margin; ++xx, p_in += cc, pout += cc, refe += cc) { |
| const double refv = igs::color::ref_value( |
| refe, cc, r_max, ref_mode); |
| if (0 == refv) { |
| for (int zz = 0; zz < cc; ++zz) { |
| pout[zz] = p_in[zz]; |
| } |
| continue; |
| } |
| |
| pout[alp] = p_in[alp]; |
| if (0 == pout[alp]) { |
| pout[red] = p_in[red]; |
| pout[gre] = p_in[gre]; |
| pout[blu] = p_in[blu]; |
| continue; |
| } |
| cl_ratw.pixel_value(p_in, xx, yy, z1, z2, static_cast<double>(p_in[alp]) / val_max, -1.0, refv, pout); |
| } |
| } |
| } |
| } else { |
| for (int yy = margin; yy < hh + margin; ++yy, p_in += 2 * margin * cc) { |
| for (int xx = margin; xx < ww + margin; ++xx, p_in += cc, pout += cc, refe += cc) { |
| const double refv = igs::color::ref_value( |
| refe, cc, r_max, ref_mode); |
| if (0 == refv) { |
| for (int zz = 0; zz < cc; ++zz) { |
| pout[zz] = p_in[zz]; |
| } |
| continue; |
| } |
| |
| cl_ratw.pixel_value(p_in, xx, yy, 0, cc - 1, -1.0, -1.0, refv, pout); |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| void igs::radial_blur::convert( |
| const unsigned char *in, const int margin |
| |
| , |
| const unsigned char *ref |
| , |
| const int ref_bits, const int ref_mode |
| |
| , |
| unsigned char *out |
| |
| , |
| const int height |
| , |
| const int width |
| , |
| const int channels, const int bits |
| |
| , |
| const double xc, const double yc, const double twist_radian, const double twist_radius |
| |
| |
| |
| |
| |
| |
| |
| , |
| const double intensity |
| |
| , |
| const double radius |
| , |
| const int sub_div |
| , |
| const bool alpha_rendering_sw) |
| { |
| if ((igs::image::rgba::siz != channels) && |
| (igs::image::rgb::siz != channels) && |
| (1 != channels) |
| ) { |
| throw std::domain_error("Bad channels,Not rgba/rgb/grayscale"); |
| } |
| |
| if ( |
| (std::numeric_limits<unsigned char>::digits != bits) && |
| (std::numeric_limits<unsigned short>::digits != bits)) { |
| throw std::domain_error("Bad in bits,Not uchar/ushort"); |
| } |
| if ((0 != ref) && |
| (std::numeric_limits<unsigned char>::digits != ref_bits) && |
| (std::numeric_limits<unsigned short>::digits != ref_bits)) { |
| throw std::domain_error("Bad ref bits,Not uchar/ushort"); |
| } |
| |
| |
| if (intensity <= 0.0 || sub_div <= 0) { |
| if (std::numeric_limits<unsigned char>::digits == bits) { |
| igs::image::copy_except_margin( |
| in, margin, out, height, width, channels); |
| } else if (std::numeric_limits<unsigned short>::digits == bits) { |
| igs::image::copy_except_margin( |
| reinterpret_cast<const unsigned short *>(in), margin, reinterpret_cast<unsigned short *>(out), height, width, channels); |
| } |
| return; |
| } |
| |
| if (0.0 == twist_radian) { |
| if (std::numeric_limits<unsigned char>::digits == ref_bits) { |
| if (std::numeric_limits<unsigned char>::digits == bits) { |
| radial_convert_template_( |
| in, margin, ref, ref_bits, ref_mode, out, height, width, channels, xc, yc, intensity, radius, sub_div, alpha_rendering_sw); |
| } else if (std::numeric_limits<unsigned short>::digits == bits) { |
| radial_convert_template_( |
| reinterpret_cast<const unsigned short *>(in), margin, ref, ref_bits, ref_mode, reinterpret_cast<unsigned short *>(out), height, width, channels, xc, yc, intensity, radius, sub_div, alpha_rendering_sw); |
| } |
| } else { |
| if (std::numeric_limits<unsigned char>::digits == bits) { |
| radial_convert_template_( |
| in, margin, reinterpret_cast<const unsigned short *>(ref), ref_bits, ref_mode, out, height, width, channels, xc, yc, intensity, radius, sub_div, alpha_rendering_sw); |
| } else if (std::numeric_limits<unsigned short>::digits == bits) { |
| radial_convert_template_( |
| reinterpret_cast<const unsigned short *>(in), margin, reinterpret_cast<const unsigned short *>(ref), ref_bits, ref_mode, reinterpret_cast<unsigned short *>(out), height, width, channels, xc, yc, intensity, radius, sub_div, alpha_rendering_sw); |
| } |
| } |
| } else { |
| if (std::numeric_limits<unsigned char>::digits == ref_bits) { |
| if (std::numeric_limits<unsigned char>::digits == bits) { |
| twist_convert_template_( |
| in, margin, ref, ref_bits, ref_mode, out, height, width, channels, xc, yc, twist_radian, twist_radius, intensity, radius, sub_div, alpha_rendering_sw); |
| } else if (std::numeric_limits<unsigned short>::digits == bits) { |
| twist_convert_template_( |
| reinterpret_cast<const unsigned short *>(in), margin, ref, ref_bits, ref_mode, reinterpret_cast<unsigned short *>(out), height, width, channels, xc, yc, twist_radian, twist_radius, intensity, radius, sub_div, alpha_rendering_sw); |
| } |
| } else { |
| if (std::numeric_limits<unsigned char>::digits == bits) { |
| twist_convert_template_( |
| in, margin, reinterpret_cast<const unsigned short *>(ref), ref_bits, ref_mode, out, height, width, channels, xc, yc, twist_radian, twist_radius, intensity, radius, sub_div, alpha_rendering_sw); |
| } else if (std::numeric_limits<unsigned short>::digits == bits) { |
| twist_convert_template_( |
| reinterpret_cast<const unsigned short *>(in), margin, reinterpret_cast<const unsigned short *>(ref), ref_bits, ref_mode, reinterpret_cast<unsigned short *>(out), height, width, channels, xc, yc, twist_radian, twist_radius, intensity, radius, sub_div, alpha_rendering_sw); |
| } |
| } |
| } |
| } |
| #if 0 |
| namespace { |
| double enlarge_margin_length_( |
| const double xc |
| ,const double yc |
| ,const double xp |
| ,const double yp |
| ,const double intensity |
| ,const double radius |
| ,const double sub_size |
| ) { |
| const double xv = xp - xc; |
| const double yv = yp - yc; |
| const double dist = sqrt(xv*xv + yv*yv); |
| |
| |
| const double len = (2.0 * dist - radius * intensity) / |
| (2.0-intensity); |
| |
| |
| |
| |
| |
| if (len <= radius) { return 0; } |
| return (len - radius) * intensity / 2.0; |
| } |
| } |
| int igs::radial_blur::enlarge_margin( |
| const int height |
| ,const int width |
| ,const double xc |
| ,const double yc |
| ,const double twist_radian |
| ,const double twist_radius |
| ,const double intensity |
| |
| ,const double radius |
| ,const int sub_div |
| ) { |
| |
| |
| if (intensity <= 0.0 || 2.0 <= intensity || sub_div <= 0) { |
| return 0; |
| } |
| |
| double margin1 = 0; |
| double margin2 = 0; |
| |
| margin1 = enlarge_margin_length_( |
| xc,yc,-width/2.0,-height/2.0,intensity,radius,1.0/sub_div); |
| |
| margin2 = enlarge_margin_length_( |
| xc,yc,-width/2.0, height/2.0,intensity,radius,1.0/sub_div); |
| if (margin1 < margin2) { margin1 = margin2; } |
| |
| margin2 = enlarge_margin_length_( |
| xc,yc, width/2.0,-height/2.0,intensity,radius,1.0/sub_div); |
| if (margin1 < margin2) { margin1 = margin2; } |
| |
| margin2 = enlarge_margin_length_( |
| xc,yc, width/2.0, height/2.0,intensity,radius,1.0/sub_div); |
| if (margin1 < margin2) { margin1 = margin2; } |
| |
| return static_cast<int>(ceil(margin1)); |
| } |
| #endif |
| namespace |
| { |
| double reference_margin_length_( |
| const double xc, const double yc, const double xp, const double yp, const double intensity, const double radius, const double sub_size) |
| { |
| const double xv = xp - xc; |
| const double yv = yp - yc; |
| const double dist = sqrt(xv * xv + yv * yv); |
| if (dist <= radius) { |
| return 0; |
| } |
| const double half_length = (dist - radius) * intensity / 2.0; |
| const double count_half = floor(half_length / sub_size); |
| return sub_size * count_half; |
| } |
| } |
| int igs::radial_blur::reference_margin( |
| const int height, const int width, const double xc, const double yc, const double twist_radian, const double twist_radius, const double intensity |
| |
| , |
| const double radius |
| , |
| const int sub_div |
| ) |
| { |
| twist_radius; |
| twist_radian; |
| |
| |
| |
| if (intensity <= 0.0 || 2.0 <= intensity || sub_div <= 0) { |
| return 0; |
| } |
| |
| double margin1 = 0; |
| double margin2 = 0; |
| |
| |
| |
| |
| margin1 = reference_margin_length_( |
| xc, yc, -width / 2.0, -height / 2.0, intensity, radius, 1.0 / sub_div); |
| |
| margin2 = reference_margin_length_( |
| xc, yc, -width / 2.0, height / 2.0, intensity, radius, 1.0 / sub_div); |
| if (margin1 < margin2) { |
| margin1 = margin2; |
| } |
| |
| margin2 = reference_margin_length_( |
| xc, yc, width / 2.0, -height / 2.0, intensity, radius, 1.0 / sub_div); |
| if (margin1 < margin2) { |
| margin1 = margin2; |
| } |
| |
| margin2 = reference_margin_length_( |
| xc, yc, width / 2.0, height / 2.0, intensity, radius, 1.0 / sub_div); |
| if (margin1 < margin2) { |
| margin1 = margin2; |
| } |
| |
| return static_cast<int>(ceil(margin1)); |
| } |