|
Shinya Kitaoka |
120a6e |
#include <vector> // std::vector</vector>
|
|
Shinya Kitaoka |
120a6e |
#include <cmath> // cos(),sin(),sqrt()</cmath>
|
|
Shinya Kitaoka |
120a6e |
#include <limits> // std::numeric_limits<t></t></limits>
|
|
Shinya Kitaoka |
120a6e |
#include <stdexcept> // std::domain_error()</stdexcept>
|
|
Toshihiro Shimizu |
890ddd |
#include "igs_ifx_common.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "igs_radial_blur.h"
|
|
shun-iwasawa |
a6544b |
|
|
shun-iwasawa |
a6544b |
#include <qvector2d></qvector2d>
|
|
shun-iwasawa |
a6544b |
#include <qtransform></qtransform>
|
|
shun-iwasawa |
a6544b |
|
|
Shinya Kitaoka |
120a6e |
namespace {
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------
|
|
shun-iwasawa |
a6544b |
enum Type { Accelerator = 0, Uniform_Length };
|
|
shun-iwasawa |
a6544b |
|
|
Shinya Kitaoka |
120a6e |
class radial_ {
|
|
shun-iwasawa |
a6544b |
const float* in_top_;
|
|
shun-iwasawa |
a6544b |
const int hh_;
|
|
shun-iwasawa |
a6544b |
const int ww_;
|
|
shun-iwasawa |
a6544b |
const int cc_;
|
|
shun-iwasawa |
a6544b |
const TPointD center_;
|
|
shun-iwasawa |
a6544b |
const bool antialias_sw_;
|
|
shun-iwasawa |
a6544b |
const bool alpha_rendering_sw_;
|
|
shun-iwasawa |
a6544b |
const double intensity_;
|
|
shun-iwasawa |
a6544b |
const double blur_radius_;
|
|
shun-iwasawa |
a6544b |
const double twist_radian_;
|
|
shun-iwasawa |
a6544b |
const double pivot_radius_;
|
|
shun-iwasawa |
a6544b |
const int type_;
|
|
shun-iwasawa |
a6544b |
const double ellipse_aspect_ratio_;
|
|
shun-iwasawa |
a6544b |
const double ellipse_angle_;
|
|
shun-iwasawa |
a6544b |
const double intensity_correlation_with_ellipse_;
|
|
shun-iwasawa |
a6544b |
QTransform tr_, tr_inv_;
|
|
shun-iwasawa |
a6544b |
|
|
Toshihiro Shimizu |
890ddd |
public:
|
|
shun-iwasawa |
a6544b |
radial_(const float* in_top, const int height, const int width,
|
|
shun-iwasawa |
a6544b |
const int channels, const TPointD center, const bool antialias_sw,
|
|
shun-iwasawa |
a6544b |
const bool alpha_rendering_sw,
|
|
shun-iwasawa |
a6544b |
const double intensity, /* 平均値ぼかし強度 */
|
|
shun-iwasawa |
a6544b |
const double blur_radius, /* 平均値ぼかしの始まる半径 */
|
|
shun-iwasawa |
a6544b |
const double twist_radian, const double pivot_radius, const int type,
|
|
shun-iwasawa |
a6544b |
const double ellipse_aspect_ratio, const double ellipse_angle,
|
|
shun-iwasawa |
a6544b |
const double intensity_correlation_with_ellipse)
|
|
Shinya Kitaoka |
120a6e |
: in_top_(in_top)
|
|
Shinya Kitaoka |
120a6e |
, hh_(height)
|
|
Shinya Kitaoka |
120a6e |
, ww_(width)
|
|
Shinya Kitaoka |
120a6e |
, cc_(channels)
|
|
shun-iwasawa |
a6544b |
, center_(center)
|
|
shun-iwasawa |
a6544b |
, antialias_sw_(antialias_sw)
|
|
shun-iwasawa |
a6544b |
, alpha_rendering_sw_(alpha_rendering_sw)
|
|
Shinya Kitaoka |
120a6e |
, intensity_(intensity)
|
|
shun-iwasawa |
a6544b |
, blur_radius_(blur_radius)
|
|
shun-iwasawa |
a6544b |
, twist_radian_(twist_radian)
|
|
shun-iwasawa |
a6544b |
, pivot_radius_(pivot_radius)
|
|
shun-iwasawa |
a6544b |
, type_(type)
|
|
shun-iwasawa |
a6544b |
, ellipse_aspect_ratio_(ellipse_aspect_ratio)
|
|
shun-iwasawa |
a6544b |
, ellipse_angle_(ellipse_angle)
|
|
shun-iwasawa |
a6544b |
, intensity_correlation_with_ellipse_(
|
|
shun-iwasawa |
a6544b |
intensity_correlation_with_ellipse) {
|
|
shun-iwasawa |
a6544b |
if (ellipse_aspect_ratio_ != 1.0) {
|
|
shun-iwasawa |
a6544b |
double axis_x =
|
|
shun-iwasawa |
a6544b |
2.0 * ellipse_aspect_ratio_ / (ellipse_aspect_ratio_ + 1.0);
|
|
shun-iwasawa |
a6544b |
double axis_y = axis_x / ellipse_aspect_ratio_;
|
|
shun-iwasawa |
a6544b |
tr_ = QTransform()
|
|
shun-iwasawa |
a6544b |
.rotateRadians(this->ellipse_angle_)
|
|
shun-iwasawa |
a6544b |
.scale(axis_x, axis_y);
|
|
shun-iwasawa |
a6544b |
tr_inv_ = QTransform(tr_).inverted();
|
|
Shinya Kitaoka |
120a6e |
}
|
|
shun-iwasawa |
a6544b |
}
|
|
shun-iwasawa |
a6544b |
void pixel_value(const float* in_current_pixel, const int xx, const int yy,
|
|
shun-iwasawa |
a6544b |
const bool isRGB, const double refVal, float* result_pixel) {
|
|
shun-iwasawa |
a6544b |
auto in_pixel = [&](int x, int y) {
|
|
shun-iwasawa |
a6544b |
/* clamp */
|
|
shun-iwasawa |
a6544b |
x = (x < 0) ? 0 : ((this->ww_ <= x) ? this->ww_ - 1 : x);
|
|
shun-iwasawa |
a6544b |
y = (y < 0) ? 0 : ((this->hh_ <= y) ? this->hh_ - 1 : y);
|
|
shun-iwasawa |
a6544b |
return this->in_top_ + this->cc_ * y * this->ww_ + this->cc_ * x;
|
|
shun-iwasawa |
a6544b |
};
|
|
shun-iwasawa |
a6544b |
auto interp = [&](float v1, float v2, float r) {
|
|
shun-iwasawa |
a6544b |
return v1 * (1.f - r) + v2 * r;
|
|
shun-iwasawa |
a6544b |
};
|
|
shun-iwasawa |
a6544b |
auto accum_interp_in_values = [&](QPointF pos, std::vector<float>& accumP,</float>
|
|
shun-iwasawa |
a6544b |
int z1, int z2, float weight) {
|
|
shun-iwasawa |
a6544b |
int xId = (int)std::floor(pos.x());
|
|
shun-iwasawa |
a6544b |
float rx = pos.x() - (float)xId;
|
|
shun-iwasawa |
a6544b |
int yId = (int)std::floor(pos.y());
|
|
shun-iwasawa |
a6544b |
float ry = pos.y() - (float)yId;
|
|
shun-iwasawa |
a6544b |
const float* p00 = in_pixel(xId, yId);
|
|
shun-iwasawa |
a6544b |
const float* p01 = in_pixel(xId + 1, yId);
|
|
shun-iwasawa |
a6544b |
const float* p10 = in_pixel(xId, yId + 1);
|
|
shun-iwasawa |
a6544b |
const float* p11 = in_pixel(xId + 1, yId + 1);
|
|
shun-iwasawa |
a6544b |
for (int zz = z1; zz <= z2; zz++) {
|
|
shun-iwasawa |
a6544b |
accumP[zz] += weight * interp(interp(p00[zz], p01[zz], rx),
|
|
shun-iwasawa |
a6544b |
interp(p10[zz], p11[zz], rx), ry);
|
|
Shinya Kitaoka |
120a6e |
}
|
|
shun-iwasawa |
a6544b |
};
|
|
shun-iwasawa |
a6544b |
auto accum_in_values = [&](QPointF pos, std::vector<float>& accumP, int z1,</float>
|
|
shun-iwasawa |
a6544b |
int z2, float weight) {
|
|
shun-iwasawa |
a6544b |
int xId = (int)std::round(pos.x());
|
|
shun-iwasawa |
a6544b |
int yId = (int)std::round(pos.y());
|
|
shun-iwasawa |
a6544b |
const float* p = in_pixel(xId, yId);
|
|
shun-iwasawa |
a6544b |
for (int zz = z1; zz <= z2; zz++) {
|
|
shun-iwasawa |
a6544b |
accumP[zz] += weight * p[zz];
|
|
Shinya Kitaoka |
120a6e |
}
|
|
shun-iwasawa |
a6544b |
};
|
|
Toshihiro Shimizu |
890ddd |
|
|
shun-iwasawa |
a6544b |
int c1, c2;
|
|
shun-iwasawa |
a6544b |
if (isRGB) {
|
|
Toshihiro Shimizu |
890ddd |
#if defined RGBA_ORDER_OF_TOONZ6
|
|
shun-iwasawa |
a6544b |
c1 = igs::image::rgba::blu;
|
|
shun-iwasawa |
a6544b |
c2 = igs::image::rgba::red;
|
|
Toshihiro Shimizu |
890ddd |
#elif defined RGBA_ORDER_OF_OPENGL
|
|
shun-iwasawa |
a6544b |
c1 = igs::image::rgba::red;
|
|
shun-iwasawa |
a6544b |
c2 = igs::image::rgba::blu;
|
|
Toshihiro Shimizu |
890ddd |
#else
|
|
shun-iwasawa |
a6544b |
Must be define / DRGBA_ORDER_OF_TOONZ6 or / DRGBA_ORDER_OF_OPENGL
|
|
Toshihiro Shimizu |
890ddd |
#endif
|
|
shun-iwasawa |
a6544b |
} else {
|
|
shun-iwasawa |
a6544b |
c1 = igs::image::rgba::alp;
|
|
shun-iwasawa |
a6544b |
c2 = igs::image::rgba::alp;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
shun-iwasawa |
a6544b |
const QPointF center(this->center_.x, this->center_.y);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
/* Pixel位置(0.5 1.5 2.5 ...) */
|
|
shun-iwasawa |
a6544b |
const QPointF p(static_cast<float>(xx) + 0.5f,</float>
|
|
shun-iwasawa |
a6544b |
static_cast<float>(yy) + 0.5f);</float>
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
/* 中心からPixel位置へのベクトルと長さ */
|
|
shun-iwasawa |
a6544b |
const QVector2D v(p - center);
|
|
shun-iwasawa |
a6544b |
const float dist = v.length();
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
/* 指定半径の範囲内なら何もしない */
|
|
shun-iwasawa |
a6544b |
bool is_in_blur_radius = false;
|
|
shun-iwasawa |
a6544b |
if (this->ellipse_aspect_ratio_ == 1.f) {
|
|
shun-iwasawa |
a6544b |
is_in_blur_radius = (dist <= this->blur_radius_);
|
|
shun-iwasawa |
a6544b |
} else {
|
|
shun-iwasawa |
a6544b |
is_in_blur_radius =
|
|
shun-iwasawa |
a6544b |
QVector2D(this->tr_inv_.map(v.toPointF())).lengthSquared() <=
|
|
shun-iwasawa |
a6544b |
(this->blur_radius_ * this->blur_radius_);
|
|
shun-iwasawa |
a6544b |
}
|
|
shun-iwasawa |
a6544b |
if (is_in_blur_radius) {
|
|
shun-iwasawa |
a6544b |
for (int c = c1; c <= c2; ++c) {
|
|
shun-iwasawa |
a6544b |
result_pixel[c] = in_current_pixel[c];
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
return;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
shun-iwasawa |
a6544b |
/* 積算値と積算回数 */
|
|
shun-iwasawa |
a6544b |
std::vector<float> accum_val(this->cc_);</float>
|
|
shun-iwasawa |
a6544b |
float accum_counter = 0.f;
|
|
shun-iwasawa |
a6544b |
|
|
Shinya Kitaoka |
120a6e |
/* Radial方向のSamplingの開始位置と終了位置 */
|
|
shun-iwasawa |
a6544b |
float scale = this->intensity_ * refVal;
|
|
shun-iwasawa |
a6544b |
|
|
shun-iwasawa |
a6544b |
float distanceRatio = 1.f;
|
|
shun-iwasawa |
a6544b |
float length;
|
|
shun-iwasawa |
a6544b |
if (this->ellipse_aspect_ratio_ == 1.) {
|
|
shun-iwasawa |
a6544b |
if (this->type_ == Accelerator)
|
|
shun-iwasawa |
a6544b |
length = (dist - this->blur_radius_) * scale;
|
|
shun-iwasawa |
a6544b |
else // Uniform_Length
|
|
shun-iwasawa |
a6544b |
length = (this->pivot_radius_ - this->blur_radius_) * scale;
|
|
shun-iwasawa |
a6544b |
} else {
|
|
shun-iwasawa |
a6544b |
float dist_mod = QVector2D(this->tr_inv_.map(v.toPointF())).length();
|
|
shun-iwasawa |
a6544b |
distanceRatio = dist / dist_mod;
|
|
shun-iwasawa |
a6544b |
if (this->type_ == Accelerator)
|
|
shun-iwasawa |
a6544b |
length = (dist - this->blur_radius_ * distanceRatio) * scale *
|
|
shun-iwasawa |
a6544b |
std::pow(distanceRatio, intensity_correlation_with_ellipse_);
|
|
shun-iwasawa |
a6544b |
else // Uniform_Length
|
|
shun-iwasawa |
a6544b |
length = (this->pivot_radius_ - this->blur_radius_) * scale *
|
|
shun-iwasawa |
a6544b |
std::pow(distanceRatio, intensity_correlation_with_ellipse_);
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
shun-iwasawa |
a6544b |
float blur_length_half = length * 0.5f;
|
|
shun-iwasawa |
a6544b |
|
|
shun-iwasawa |
a6544b |
// sampling in both directions
|
|
shun-iwasawa |
a6544b |
float sample_length = 0.f;
|
|
shun-iwasawa |
a6544b |
while (sample_length < blur_length_half) {
|
|
shun-iwasawa |
a6544b |
// compute weight
|
|
shun-iwasawa |
a6544b |
float weight = 1.f;
|
|
shun-iwasawa |
a6544b |
if (sample_length > blur_length_half - 1.f) {
|
|
shun-iwasawa |
a6544b |
if (antialias_sw_)
|
|
shun-iwasawa |
a6544b |
weight = blur_length_half - sample_length;
|
|
shun-iwasawa |
a6544b |
else
|
|
shun-iwasawa |
a6544b |
break;
|
|
shun-iwasawa |
a6544b |
}
|
|
shun-iwasawa |
a6544b |
// advance to the next sample
|
|
shun-iwasawa |
a6544b |
sample_length += weight;
|
|
shun-iwasawa |
a6544b |
|
|
shun-iwasawa |
a6544b |
float sample_dists[2] = {dist + sample_length, dist - sample_length};
|
|
shun-iwasawa |
a6544b |
for (int i = 0; i < 2; i++) {
|
|
shun-iwasawa |
a6544b |
if (sample_dists[i] < 0.f) continue; // 中心を突き抜けた場合は無視する
|
|
shun-iwasawa |
a6544b |
QPointF v_smpl;
|
|
shun-iwasawa |
a6544b |
float scaleVal = sample_dists[i] / dist;
|
|
shun-iwasawa |
a6544b |
if (this->twist_radian_ == 0.0) {
|
|
shun-iwasawa |
a6544b |
if (this->ellipse_aspect_ratio_ == 1.f)
|
|
shun-iwasawa |
a6544b |
v_smpl = v.toPointF() * scaleVal;
|
|
shun-iwasawa |
a6544b |
else
|
|
shun-iwasawa |
a6544b |
v_smpl = (this->tr_inv_ *
|
|
shun-iwasawa |
a6544b |
QTransform(this->tr_).scale(scaleVal, scaleVal))
|
|
shun-iwasawa |
a6544b |
.map(v.toPointF());
|
|
shun-iwasawa |
a6544b |
} else { // twisted case
|
|
shun-iwasawa |
a6544b |
if (this->ellipse_aspect_ratio_ == 1.f) {
|
|
shun-iwasawa |
a6544b |
double tmp_twist_angle =
|
|
shun-iwasawa |
a6544b |
twist_radian_ * (sample_dists[i] - dist) / pivot_radius_;
|
|
shun-iwasawa |
a6544b |
|
|
shun-iwasawa |
a6544b |
float cos = std::cos(tmp_twist_angle);
|
|
shun-iwasawa |
a6544b |
float sin = std::sin(tmp_twist_angle);
|
|
shun-iwasawa |
a6544b |
|
|
shun-iwasawa |
a6544b |
v_smpl =
|
|
shun-iwasawa |
a6544b |
QPointF(cos * v.x() - sin * v.y(), sin * v.x() + cos * v.y()) *
|
|
shun-iwasawa |
a6544b |
scaleVal;
|
|
shun-iwasawa |
a6544b |
} else {
|
|
shun-iwasawa |
a6544b |
double tmp_twist_angle = twist_radian_ * (sample_dists[i] - dist) *
|
|
shun-iwasawa |
a6544b |
distanceRatio / pivot_radius_;
|
|
shun-iwasawa |
a6544b |
v_smpl = (this->tr_inv_ * QTransform(this->tr_)
|
|
shun-iwasawa |
a6544b |
.rotateRadians(tmp_twist_angle)
|
|
shun-iwasawa |
a6544b |
.scale(scaleVal, scaleVal))
|
|
shun-iwasawa |
a6544b |
.map(v.toPointF());
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
}
|
|
shun-iwasawa |
a6544b |
|
|
shun-iwasawa |
a6544b |
if (antialias_sw_)
|
|
shun-iwasawa |
a6544b |
accum_interp_in_values(v_smpl + center, accum_val, c1, c2, weight);
|
|
shun-iwasawa |
a6544b |
else
|
|
shun-iwasawa |
a6544b |
accum_in_values(v_smpl + center, accum_val, c1, c2, weight);
|
|
shun-iwasawa |
a6544b |
accum_counter += weight;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
}
|
|
shun-iwasawa |
a6544b |
// sample the original pos
|
|
shun-iwasawa |
a6544b |
if (antialias_sw_)
|
|
shun-iwasawa |
a6544b |
accum_interp_in_values(p, accum_val, c1, c2, 1.f);
|
|
shun-iwasawa |
a6544b |
else
|
|
shun-iwasawa |
a6544b |
accum_in_values(p, accum_val, c1, c2, 1.f);
|
|
shun-iwasawa |
a6544b |
accum_counter += 1.f;
|
|
shun-iwasawa |
a6544b |
|
|
Shinya Kitaoka |
120a6e |
/* 積算しなかったとき(念のためのCheck) */
|
|
shun-iwasawa |
a6544b |
if (accum_counter <= 0.f) {
|
|
shun-iwasawa |
a6544b |
for (int c = c1; c <= c2; ++c) {
|
|
shun-iwasawa |
a6544b |
result_pixel[c] = in_current_pixel[c];
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
return;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
/* ここで画像Pixelに保存 */
|
|
shun-iwasawa |
a6544b |
for (int c = c1; c <= c2; ++c) {
|
|
shun-iwasawa |
a6544b |
accum_val[c] /= accum_counter;
|
|
shun-iwasawa |
a6544b |
|
|
shun-iwasawa |
a6544b |
if (isRGB && !this->alpha_rendering_sw_ &&
|
|
shun-iwasawa |
a6544b |
(in_current_pixel[c] < accum_val[c]) &&
|
|
shun-iwasawa |
a6544b |
result_pixel[igs::image::rgba::alp] < 1.f) {
|
|
shun-iwasawa |
a6544b |
result_pixel[c] =
|
|
shun-iwasawa |
a6544b |
in_current_pixel[c] + (accum_val[c] - in_current_pixel[c]) *
|
|
shun-iwasawa |
a6544b |
result_pixel[igs::image::rgba::alp];
|
|
Shinya Kitaoka |
120a6e |
} else {
|
|
shun-iwasawa |
a6544b |
result_pixel[c] = accum_val[c];
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
private:
|
|
shun-iwasawa |
a6544b |
radial_();
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
/* copy constructorを無効化 */
|
|
shun-iwasawa |
a6544b |
radial_(const radial_&);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
/* 代入演算子を無効化 */
|
|
shun-iwasawa |
a6544b |
radial_& operator=(const radial_&);
|
|
Toshihiro Shimizu |
890ddd |
};
|
|
Shinya Kitaoka |
120a6e |
|
|
shun-iwasawa |
a6544b |
void radial_convert(
|
|
shun-iwasawa |
a6544b |
const float* in, float* out, const int margin, /* 参照画像(in)がもつ余白 */
|
|
shun-iwasawa |
a6544b |
const TDimension out_dim, /* 求める画像(out)のサイズ */
|
|
shun-iwasawa |
a6544b |
const int channels, const float* ref, /* 求める画像(out)と同じ高さ、幅 */
|
|
shun-iwasawa |
a6544b |
const TPointD center,
|
|
shun-iwasawa |
a6544b |
const double intensity, /* 強度。ゼロより大きく2以下 */
|
|
shun-iwasawa |
a6544b |
/* radius円境界での平均値ぼかしゼロとするためintensityは2より小さい */
|
|
shun-iwasawa |
a6544b |
const double radius, /* 平均値ぼかしの始まる半径 */
|
|
shun-iwasawa |
a6544b |
const double twist_radian, const double pivot_radius,
|
|
shun-iwasawa |
a6544b |
const int type, // 0: Accelerator, 1: Uniform Length
|
|
shun-iwasawa |
a6544b |
const bool antialias_sw, /* when true, sampled pixel will be
|
|
shun-iwasawa |
a6544b |
bilinear-interpolated */
|
|
shun-iwasawa |
a6544b |
const bool alpha_rendering_sw, const double ellipse_aspect_ratio,
|
|
shun-iwasawa |
a6544b |
const double ellipse_angle,
|
|
shun-iwasawa |
a6544b |
const double intensity_correlation_with_ellipse) {
|
|
shun-iwasawa |
a6544b |
assert(intensity > 0.0);
|
|
shun-iwasawa |
a6544b |
|
|
shun-iwasawa |
a6544b |
radial_ radial(in, out_dim.ly + margin * 2, out_dim.lx + margin * 2, channels,
|
|
shun-iwasawa |
a6544b |
center, antialias_sw, alpha_rendering_sw, intensity, radius,
|
|
shun-iwasawa |
a6544b |
twist_radian, pivot_radius, type, ellipse_aspect_ratio,
|
|
shun-iwasawa |
a6544b |
ellipse_angle * M_PI_180, intensity_correlation_with_ellipse);
|
|
shun-iwasawa |
a6544b |
|
|
shun-iwasawa |
a6544b |
const float* p_in =
|
|
shun-iwasawa |
a6544b |
in + margin * (out_dim.lx + margin * 2) * channels + margin * channels;
|
|
shun-iwasawa |
a6544b |
|
|
shun-iwasawa |
a6544b |
float* p_out = out;
|
|
shun-iwasawa |
a6544b |
const float* p_ref = ref;
|
|
shun-iwasawa |
a6544b |
|
|
shun-iwasawa |
a6544b |
for (int yy = margin; yy < out_dim.ly + margin;
|
|
shun-iwasawa |
a6544b |
++yy, p_in += 2 * margin * channels) {
|
|
shun-iwasawa |
a6544b |
for (int xx = margin; xx < out_dim.lx + margin;
|
|
shun-iwasawa |
a6544b |
++xx, p_in += channels, p_out += channels) {
|
|
Shinya Kitaoka |
120a6e |
using namespace igs::image::rgba;
|
|
shun-iwasawa |
a6544b |
float refVal = (ref) ? *p_ref : 1.f;
|
|
shun-iwasawa |
a6544b |
|
|
shun-iwasawa |
a6544b |
// if the reference value is zero
|
|
shun-iwasawa |
a6544b |
if (refVal == 0.f) {
|
|
shun-iwasawa |
a6544b |
for (int c = 0; c < channels; ++c) p_out[c] = p_in[c];
|
|
shun-iwasawa |
a6544b |
p_ref++;
|
|
shun-iwasawa |
a6544b |
continue;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
shun-iwasawa |
a6544b |
|
|
shun-iwasawa |
a6544b |
if (alpha_rendering_sw) { // blur alpha
|
|
shun-iwasawa |
a6544b |
radial.pixel_value(p_in, xx, yy, false, refVal, p_out);
|
|
shun-iwasawa |
a6544b |
} else { // use the src alpha as-is
|
|
shun-iwasawa |
a6544b |
p_out[alp] = p_in[alp];
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
shun-iwasawa |
a6544b |
if (p_out[alp] == 0.f) {
|
|
shun-iwasawa |
a6544b |
p_out[red] = p_in[red];
|
|
shun-iwasawa |
a6544b |
p_out[gre] = p_in[gre];
|
|
shun-iwasawa |
a6544b |
p_out[blu] = p_in[blu];
|
|
shun-iwasawa |
a6544b |
if (ref) p_ref++;
|
|
shun-iwasawa |
a6544b |
continue;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
shun-iwasawa |
a6544b |
|
|
shun-iwasawa |
a6544b |
// blur RGB channels
|
|
shun-iwasawa |
a6544b |
radial.pixel_value(p_in, xx, yy, true, refVal, p_out);
|
|
shun-iwasawa |
a6544b |
|
|
shun-iwasawa |
a6544b |
if (ref) p_ref++;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
shun-iwasawa |
a6544b |
} // namespace
|
|
shun-iwasawa |
a6544b |
|
|
Toshihiro Shimizu |
890ddd |
//--------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
void igs::radial_blur::convert(
|
|
shun-iwasawa |
a6544b |
const float* in, float* out, const int margin, /* 参照画像(in)がもつ余白 */
|
|
shun-iwasawa |
a6544b |
const TDimension out_dim, /* 求める画像(out)の大きさ*/
|
|
shun-iwasawa |
a6544b |
const int channels, const float* ref, /* outと同じ高さ、幅 */
|
|
shun-iwasawa |
a6544b |
const TPointD center, const double twist_radian, const double twist_radius,
|
|
shun-iwasawa |
a6544b |
const double intensity, /* 強度。ゼロより大きく2以下 */
|
|
Shinya Kitaoka |
120a6e |
/* radius円境界での平均値ぼかしゼロとするためintensityは2より小さい */
|
|
shun-iwasawa |
a6544b |
const double radius, /* 平均値ぼかしの始まる半径 */
|
|
shun-iwasawa |
a6544b |
const int type, const bool antialias_sw, const bool alpha_rendering_sw,
|
|
shun-iwasawa |
a6544b |
const double ellipse_aspect_ratio, const double ellipse_angle,
|
|
shun-iwasawa |
a6544b |
const double intensity_correlation_with_ellipse) {
|
|
shun-iwasawa |
a6544b |
/* 強度のないとき */
|
|
shun-iwasawa |
a6544b |
if (intensity <= 0.0) {
|
|
shun-iwasawa |
a6544b |
igs::image::copy_except_margin(in, margin, out, out_dim.ly, out_dim.lx,
|
|
shun-iwasawa |
a6544b |
channels);
|
|
Shinya Kitaoka |
120a6e |
return;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
shun-iwasawa |
a6544b |
radial_convert(in, out, margin, out_dim, channels, ref, center, intensity,
|
|
shun-iwasawa |
a6544b |
radius, twist_radian, twist_radius, type, antialias_sw,
|
|
shun-iwasawa |
a6544b |
alpha_rendering_sw, ellipse_aspect_ratio, ellipse_angle,
|
|
shun-iwasawa |
a6544b |
intensity_correlation_with_ellipse);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
shun-iwasawa |
a6544b |
//-------------------- comment out end -------------------------
|
|
Toshihiro Shimizu |
890ddd |
namespace {
|
|
shun-iwasawa |
a6544b |
|
|
shun-iwasawa |
a6544b |
double reference_margin_length_(const TPointD center, const double xp,
|
|
shun-iwasawa |
a6544b |
const double yp, const double intensity,
|
|
shun-iwasawa |
a6544b |
const double radius, const double pivot_radius,
|
|
shun-iwasawa |
a6544b |
const int type,
|
|
shun-iwasawa |
a6544b |
const double ellipse_aspect_ratio,
|
|
shun-iwasawa |
a6544b |
const double intensity_correlation_with_ellipse,
|
|
shun-iwasawa |
a6544b |
const QTransform& tr_inv) {
|
|
shun-iwasawa |
a6544b |
const QPointF c(center.x, center.y);
|
|
shun-iwasawa |
a6544b |
const QPointF p(xp, yp);
|
|
shun-iwasawa |
a6544b |
const QVector2D v(p - c);
|
|
shun-iwasawa |
a6544b |
const float dist = v.length();
|
|
Shinya Kitaoka |
120a6e |
if (dist <= radius) {
|
|
Shinya Kitaoka |
120a6e |
return 0;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
shun-iwasawa |
a6544b |
double length;
|
|
shun-iwasawa |
a6544b |
if (ellipse_aspect_ratio == 1.) {
|
|
shun-iwasawa |
a6544b |
if (type == Accelerator)
|
|
shun-iwasawa |
a6544b |
length = (dist - radius) * intensity;
|
|
shun-iwasawa |
a6544b |
else
|
|
shun-iwasawa |
a6544b |
length = (pivot_radius - radius) * intensity;
|
|
shun-iwasawa |
a6544b |
} else {
|
|
shun-iwasawa |
a6544b |
float dist_mod = QVector2D(tr_inv.map(v.toPointF())).length();
|
|
shun-iwasawa |
a6544b |
double distanceRatio = dist / dist_mod;
|
|
shun-iwasawa |
a6544b |
if (type == Accelerator)
|
|
shun-iwasawa |
a6544b |
length = (dist - radius * distanceRatio) * intensity *
|
|
shun-iwasawa |
a6544b |
std::pow(distanceRatio, intensity_correlation_with_ellipse);
|
|
shun-iwasawa |
a6544b |
else // Uniform_Length
|
|
shun-iwasawa |
a6544b |
length = (pivot_radius - radius) * intensity *
|
|
shun-iwasawa |
a6544b |
std::pow(distanceRatio, intensity_correlation_with_ellipse);
|
|
shun-iwasawa |
a6544b |
}
|
|
shun-iwasawa |
a6544b |
return length;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
shun-iwasawa |
a6544b |
|
|
shun-iwasawa |
a6544b |
} // namespace
|
|
Shinya Kitaoka |
120a6e |
int igs::radial_blur::
|
|
Shinya Kitaoka |
120a6e |
reference_margin(/* Twist時は正確ではない... */
|
|
shun-iwasawa |
a6544b |
const int height, const int width, const TPointD center,
|
|
shun-iwasawa |
a6544b |
const double twist_radian, const double twist_radius,
|
|
shun-iwasawa |
a6544b |
const double intensity, /* 強度。ゼロより大きく2以下 */
|
|
Shinya Kitaoka |
120a6e |
/* radius円境界での平均値ぼかしゼロとするためintensityは2より小さい
|
|
shun-iwasawa |
a6544b |
*/
|
|
shun-iwasawa |
a6544b |
const double radius, /* 平均値ぼかしの始まる半径 */
|
|
shun-iwasawa |
a6544b |
const int type, const double ellipse_aspect_ratio,
|
|
shun-iwasawa |
a6544b |
const double ellipse_angle,
|
|
shun-iwasawa |
a6544b |
const double intensity_correlation_with_ellipse) {
|
|
shun-iwasawa |
a6544b |
/* 強度のないとき、2以上のとき、なにもしない */
|
|
shun-iwasawa |
a6544b |
if (intensity <= 0.0 || 2.0 <= intensity) {
|
|
Shinya Kitaoka |
120a6e |
return 0;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
double margin1 = 0;
|
|
Shinya Kitaoka |
120a6e |
double margin2 = 0;
|
|
Shinya Kitaoka |
120a6e |
|
|
shun-iwasawa |
a6544b |
QTransform tr_inv;
|
|
shun-iwasawa |
a6544b |
if (ellipse_aspect_ratio != 1.0) {
|
|
shun-iwasawa |
a6544b |
double axis_x = 2.0 * ellipse_aspect_ratio / (ellipse_aspect_ratio + 1.0);
|
|
shun-iwasawa |
a6544b |
double axis_y = axis_x / ellipse_aspect_ratio;
|
|
shun-iwasawa |
a6544b |
tr_inv = QTransform()
|
|
shun-iwasawa |
a6544b |
.rotateRadians(ellipse_angle)
|
|
shun-iwasawa |
a6544b |
.scale(axis_x, axis_y)
|
|
shun-iwasawa |
a6544b |
.inverted();
|
|
shun-iwasawa |
a6544b |
}
|
|
shun-iwasawa |
a6544b |
|
|
Shinya Kitaoka |
120a6e |
/*
|
|
Shinya Kitaoka |
120a6e |
四隅から参照する外部への最大マージンを計算する
|
|
Shinya Kitaoka |
120a6e |
*/
|
|
shun-iwasawa |
a6544b |
margin1 = reference_margin_length_(
|
|
shun-iwasawa |
a6544b |
center, -width / 2.0, -height / 2.0, intensity, radius, twist_radius,
|
|
shun-iwasawa |
a6544b |
type, ellipse_aspect_ratio, intensity_correlation_with_ellipse, tr_inv);
|
|
Shinya Kitaoka |
120a6e |
|
|
shun-iwasawa |
a6544b |
margin2 = reference_margin_length_(
|
|
shun-iwasawa |
a6544b |
center, -width / 2.0, height / 2.0, intensity, radius, twist_radius, type,
|
|
shun-iwasawa |
a6544b |
ellipse_aspect_ratio, intensity_correlation_with_ellipse, tr_inv);
|
|
Shinya Kitaoka |
120a6e |
if (margin1 < margin2) {
|
|
Shinya Kitaoka |
120a6e |
margin1 = margin2;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
shun-iwasawa |
a6544b |
margin2 = reference_margin_length_(
|
|
shun-iwasawa |
a6544b |
center, width / 2.0, -height / 2.0, intensity, radius, twist_radius, type,
|
|
shun-iwasawa |
a6544b |
ellipse_aspect_ratio, intensity_correlation_with_ellipse, tr_inv);
|
|
Shinya Kitaoka |
120a6e |
if (margin1 < margin2) {
|
|
Shinya Kitaoka |
120a6e |
margin1 = margin2;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
shun-iwasawa |
a6544b |
margin2 = reference_margin_length_(
|
|
shun-iwasawa |
a6544b |
center, width / 2.0, height / 2.0, intensity, radius, twist_radius, type,
|
|
shun-iwasawa |
a6544b |
ellipse_aspect_ratio, intensity_correlation_with_ellipse, tr_inv);
|
|
Shinya Kitaoka |
120a6e |
if (margin1 < margin2) {
|
|
Shinya Kitaoka |
120a6e |
margin1 = margin2;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
return static_cast<int>(ceil(margin1));</int>
|
|
Toshihiro Shimizu |
890ddd |
}
|