18#include <boost/multi_array.hpp>
62 void Init(quint8* _data,
int _imageWidth,
int _imageHeight,
int _pixelSize)
77 ImageView(quint8* _data,
int _imageWidth,
int _imageHeight,
int _pixelSize)
79 Init(_data, _imageWidth, _imageHeight, _pixelSize);
109 if (
this != &other) {
112 Init(other.data(), other.m_imageWidth, other.m_imageHeight, other.m_pixelSize);
113 other.m_data =
nullptr;
164 void Init(
int _imageWidth,
int _imageHeight,
int _pixelSize)
166 m_data =
new quint8[ _imageWidth * _imageHeight * _pixelSize ];
172 Init(_imageWidth, _imageHeight, _pixelSize);
180 m_data =
new quint8[ imageSize.width()*imageSize.height()*cs->
pixelSize() ];
181 imageDev->
readBytes(
m_data, imageSize.x(), imageSize.y(), imageSize.width(), imageSize.height());
187 Init(imageDev, imageSize);
233 v = (v > MASK_CLEAR) ? MASK_SET : MASK_CLEAR;
277 distance = &distance_impl<KoRgbU8Traits::channels_type>;
280 distance = &distance_impl<KoRgbU16Traits::channels_type>;
283 distance = &distance_impl<KoRgbF16Traits::channels_type>;
286 distance = &distance_impl<KoRgbF32Traits::channels_type>;
289 distance = &distance_impl<KoRgbF64Traits::channels_type>;
301 int newW = W / 2, newH = H / 2;
348 for (
int y = 0; y < newH; ++y) {
349 for (
int x = 0; x < newW; ++x) {
352 int xs = (x * W) / newW;
353 int ys = (y * H) / newH;
360 std::fill(newImage(x, y), newImage(x, y) + newImage.
pixel_size(), 0);
383 clone->cs = this->
cs;
384 clone->csMask = this->
csMask;
392 return v > MASK_CLEAR;
405 for (
int dy = -
S; dy <=
S; ++dy) {
410 for (
int dx = -
S; dx <=
S; ++dx) {
443 inline void mixColors(std::vector< quint8* > pixels, std::vector< float > w,
float wsum, quint8* dst)
448 assert(pixels.size() == n);
449 std::vector< qint16 > weights;
454 float scale = 255 / (wsum + 0.001);
458 float v1 =
v * scale + dif;
459 float v2 = std::round(v1);
461 weights.push_back(v2);
464 mixOp->
mixColors(pixels.data(), weights.data(), n, dst);
485 T *v1 =
reinterpret_cast<T*
>(my.
imageData(x, y));
486 T *v2 =
reinterpret_cast<T*
>(other.
imageData(xo, yo));
488 for (quint32 chan = 0; chan < nchannels; chan++) {
490 float v = ((float)(*(v1 + chan)) - (
float)(*(v2 + chan)));
522 return rand() % range;
528 for (
int y = 0; y <
imSize.height(); y++) {
529 for (
int x = 0; x <
imSize.width(); x++) {
534 const int maxretry = 20;
547 float s_zero = 0.999;
548 float t_halfmax = 0.10;
550 float x = (s_zero - 0.5) * 2;
551 float invtanh = 0.5 * std::log((1. + x) / (1. - x));
552 float coef = invtanh / t_halfmax;
555 for (
int i = 0; i < (int)
similarity.size(); i++) {
557 similarity[i] = 0.5 - 0.5 * std::tanh(coef * (t - t_halfmax));
585 for (
int y = 0; y <
imSize.height(); y++) {
586 for (
int x = 0; x <
imSize.width(); x++) {
598 float xscale = qreal(
imSize.width()) / nnf.
imSize.width();
599 float yscale = qreal(
imSize.height()) / nnf.
imSize.height();
601 for (
int y = 0; y <
imSize.height(); y++) {
602 for (
int x = 0; x <
imSize.width(); x++) {
603 int xlow = std::min((
int)(x / xscale), nnf.
imSize.width() - 1);
604 int ylow = std::min((
int)(y / yscale), nnf.
imSize.height() - 1);
606 field[x][y].x = nnf.
field[xlow][ylow].x * xscale;
607 field[x][y].y = nnf.
field[xlow][ylow].y * yscale;
619 int max_x =
imSize.width() - 1;
620 int max_y =
imSize.height() - 1;
622 for (
int i = 0; i < pass; i++) {
624 for (
int y = min_y; y < max_y; y++)
625 for (
int x = min_x; x <= max_x; x++)
630 for (
int y = max_y; y >= min_y; y--)
631 for (
int x = max_x; x >= min_x; x--)
642 if (x - dir > 0 && x - dir <
imSize.width()) {
643 xp =
field[x - dir][y].x + dir;
644 yp =
field[x - dir][y].y;
649 field[x][y].distance = dp;
654 if (y - dir > 0 && y - dir <
imSize.height()) {
655 xp =
field[x][y - dir].x;
656 yp =
field[x][y - dir].y + dir;
661 field[x][y].distance = dp;
667 int xpi =
field[x][y].x;
668 int ypi =
field[x][y].y;
672 xp = std::max(0, std::min(
output->
size().width() - 1, xp));
673 yp = std::max(0, std::min(
output->
size().height() - 1, yp));
679 field[x][y].distance = dp;
690 const qint64 ssdmax =
nColors * 255 * (qint64)255;
699 if (xks < 0 || xks >=
input->
size().width()) {
704 if (yks < 0 || yks >=
input->
size().height()) {
718 if (xkt < 0 || xkt >=
output->
size().width()) {
722 if (ykt < 0 || ykt >=
output->
size().height()) {
785 QRect size =
source->size();
788 while ((size.width() >
radius) && (size.height() >
radius) &&
source->countMasked() > 0) {
804 for (
int level = maxlevel - 1; level > 0; level--) {
807 if (level == maxlevel - 1) {
832 int iterEM = std::min(2 * level, 4);
833 int iterNNF = std::min(5, 1 + level);
840 for (
int emloop = 1; emloop <= iterEM; emloop++) {
842 if (!newtarget.
isNull()) {
843 nnf_TargetToSource->
input = newtarget;
848 for (
int x = 0; x <
target->size().width(); ++x) {
849 for (
int y = 0; y <
target->size().height(); ++y) {
850 if (!
source->containsMasked(x, y, radius)) {
851 nnf_TargetToSource->
field[x][y].x = x;
852 nnf_TargetToSource->
field[x][y].y = y;
853 nnf_TargetToSource->
field[x][y].distance = 0;
859 nnf_TargetToSource->
minimize(iterNNF);
863 bool upscaled =
false;
867 if (level >= 1 && (emloop == iterEM)) {
868 newsource = pyramid.at(level - 1);
869 QRect sz = newsource->
size();
870 newtarget =
target->copy();
871 newtarget->
upscale(sz.width(), sz.height());
874 newsource = pyramid.at(level);
875 newtarget =
target->copy();
897 int H_target =
target->size().height();
898 int W_target =
target->size().width();
899 int H_source =
source->size().height();
900 int W_source =
source->size().width();
902 std::vector< quint8* > pixels;
903 std::vector< float > weights;
904 pixels.reserve(
R *
R);
905 weights.reserve(
R *
R);
906 for (
int x = 0 ; x < W_target ; ++x) {
907 for (
int y = 0 ; y < H_target; ++y) {
913 if (!
source->containsMasked(x, y,
R + 4) ) {
915 pixels.push_back(
source->getImagePixel(x, y));
916 weights.push_back(1.f);
917 target->mixColors(pixels, weights, 1.f,
target->getImagePixel(x, y));
919 for (
int dx = -
R ; dx <=
R; ++dx) {
920 for (
int dy = -
R ; dy <=
R ; ++dy) {
929 if (xpt < 0 || xpt >= W_nnf || ypt < 0 || ypt >= H_nnf)
932 xst = nnf->
field[xpt][ypt].x;
933 yst = nnf->
field[xpt][ypt].y;
934 int dp = nnf->
field[xpt][ypt].distance;
939 if (xpt < 0 || (xpt / 2) >= W_nnf || ypt < 0 || (ypt / 2) >= H_nnf)
941 xst = 2 * nnf->
field[xpt / 2][ypt / 2].x + (xpt % 2);
942 yst = 2 * nnf->
field[xpt / 2][ypt / 2].y + (ypt % 2);
943 int dp = nnf->
field[xpt / 2][ypt / 2].distance;
951 if (xs < 0 || xs >= W_source || ys < 0 || ys >= H_source)
954 if (
source->isMasked(xs, ys))
957 pixels.push_back(
source->getImagePixel(xs, ys));
958 weights.push_back(w);
966 target->mixColors(pixels, weights, wsum,
target->getImagePixel(x, y));
984 float scale = 1.0 + (accuracy / 25.0);
985 int dx = maskRect.width() * scale;
986 int dy = maskRect.height() * scale;
987 maskRect.adjust(-dx, -dy, dx, dy);
988 maskRect = maskRect.intersected(imageRect);
990 if (!maskRect.isEmpty()) {
991 Inpaint inpaint(imageDev, maskDev, patchRadius, maskRect);
float value(const T *src, size_t ch)
Eigen::Matrix< double, 4, 2 > S
Eigen::Matrix< double, 4, 2 > R
KisMagneticGraph::vertex_descriptor target(typename KisMagneticGraph::edge_descriptor e, KisMagneticGraph g)
KisMagneticGraph::vertex_descriptor source(typename KisMagneticGraph::edge_descriptor e, KisMagneticGraph g)
const KoID Float32BitsColorDepthID("F32", ki18n("32-bit float/channel"))
const KoID Float64BitsColorDepthID("F64", ki18n("64-bit float/channel"))
const KoID Float16BitsColorDepthID("F16", ki18n("16-bit float/channel"))
const KoID Integer16BitsColorDepthID("U16", ki18n("16-bit integer/channel"))
void Init(int _imageWidth, int _imageHeight, int _pixelSize)
ImageData(KisPaintDeviceSP imageDev, const QRect &imageSize)
ImageData(int _imageWidth, int _imageHeight, int _pixelSize)
void Init(KisPaintDeviceSP imageDev, const QRect &imageSize)
quint8 * data(void) const
void DebugDump(const QString &fnamePrefix)
int pixel_size(void) const
ImageView & operator=(const ImageView &other)
ImageView & operator=(ImageView &&other) noexcept
quint8 * operator()(int x, int y) const
ImageView(quint8 *_data, int _imageWidth, int _imageHeight, int _pixelSize)
void saveToDevice(KisPaintDeviceSP outDev, QRect rect)
void Init(quint8 *_data, int _imageWidth, int _imageHeight, int _pixelSize)
int num_bytes(void) const
int num_elements(void) const
MaskedImageSP patch_simple(void)
NearestNeighborFieldSP nnf_SourceToTarget
KisPaintDeviceSP devCache
QList< MaskedImageSP > pyramid
Inpaint(KisPaintDeviceSP dev, KisPaintDeviceSP devMask, int _radius, QRect maskRect)
NearestNeighborFieldSP nnf_TargetToSource
MaskedImageSP patch(void)
static KisFilterStrategyRegistry * instance()
QRect nonDefaultPixelArea() const
void setDefaultBounds(KisDefaultBoundsBaseSP bounds)
QRect exactBounds() const
const KoColorSpace * colorSpace() const
KisDefaultBoundsBaseSP defaultBounds() const
void readBytes(quint8 *data, qint32 x, qint32 y, qint32 w, qint32 h) const
void writeBytes(const quint8 *data, qint32 x, qint32 y, qint32 w, qint32 h)
static void copyAreaOptimized(const QPoint &dstPt, KisPaintDeviceSP src, KisPaintDeviceSP dst, const QRect &originalSrcRect)
virtual quint32 pixelSize() const =0
virtual quint8 scaleToU8(const quint8 *srcPixel, qint32 channelPos) const =0
virtual quint32 channelCount() const =0
virtual KoID colorDepthId() const =0
virtual void normalisedChannelsValue(const quint8 *pixel, QVector< float > &channels) const =0
virtual void fromNormalisedChannelsValue(quint8 *pixel, const QVector< float > &values) const =0
KoMixColorsOp * mixColorsOp
A holder for an updater that does nothing.
const T value(const QString &id) const
virtual void mixColors(const quint8 *const *colors, const qint16 *weights, int nColors, quint8 *dst, int weightSum=255) const =0
int channelCount(void) const
friend float distance_impl(const MaskedImage &my, int x, int y, const MaskedImage &other, int xo, int yo)
void toPaintDevice(KisPaintDeviceSP imageDev, QRect rect, KisSelectionSP selection)
void cacheMask(KisPaintDeviceSP maskDev, QRect rect)
bool containsMasked(int x, int y, int S)
const KoColorSpace * csMask
void mixColors(std::vector< quint8 * > pixels, std::vector< float > w, float wsum, quint8 *dst)
void upscale(int newW, int newH)
KisSharedPtr< MaskedImage > copy(void)
void cacheImage(KisPaintDeviceSP imageDev, QRect rect)
quint8 getImagePixelU8(int x, int y, int chan) const
void setMask(int x, int y, quint8 v)
QVector< float > getImagePixels(int x, int y) const
bool isMasked(int x, int y)
quint8 * getImagePixel(int x, int y)
void DebugDump(const QString &name)
std::function< float(const MaskedImage &, int, int, const MaskedImage &, int, int) distance)
MaskedImage(KisPaintDeviceSP _imageDev, KisPaintDeviceSP _maskDev, QRect _maskRect)
void initialize(KisPaintDeviceSP _imageDev, KisPaintDeviceSP _maskDev, QRect _maskRect)
void setImagePixels(int x, int y, QVector< float > &value)
void minimizeLink(int x, int y, int dir)
NearestNeighborField(const MaskedImageSP _input, MaskedImageSP _output, int _patchsize)
static MaskedImageSP ExpectationMaximization(KisSharedPtr< NearestNeighborField > TargetToSource, int level, int radius, QList< MaskedImageSP > &pyramid)
static void ExpectationStep(KisSharedPtr< NearestNeighborField > nnf, MaskedImageSP source, MaskedImageSP target, bool upscale)
void initialize(const NearestNeighborField &nnf)
void init_similarity_curve(void)
int distance(int x, int y, int xp, int yp)
void EM_Step(MaskedImageSP source, MaskedImageSP target, int R, bool upscaled)
std::vector< float > similarity
QList< KoChannelInfo * > channels
float distance_impl(const MaskedImage &my, int x, int y, const MaskedImage &other, int xo, int yo)
boost::multi_array< NNPixel, 2 > NNArray_type
KisSharedPtr< NearestNeighborField > NearestNeighborFieldSP
boost::multi_array< Vote_elem, 2 > Vote_type
QRect getMaskBoundingBox(KisPaintDeviceSP maskDev)
QRect patchImage(const KisPaintDeviceSP imageDev, const KisPaintDeviceSP maskDev, int patchRadius, int accuracy, KisSelectionSP selection)
KisSharedPtr< MaskedImage > MaskedImageSP
#define KIS_DUMP_DEVICE_2(device, rc, suffix, prefix)
const KoColorSpace * colorSpace(const QString &colorModelId, const QString &colorDepthId, const KoColorProfile *profile)
static KoColorSpaceRegistry * instance()
const KoColorSpace * alpha8()
QVector< float > channel_values