Krita Source Code Documentation
Loading...
Searching...
No Matches
NearestNeighborField Class Reference
+ Inheritance diagram for NearestNeighborField:

Public Member Functions

int distance (int x, int y, int xp, int yp)
 
void EM_Step (MaskedImageSP source, MaskedImageSP target, int R, bool upscaled)
 
void initialize (const NearestNeighborField &nnf)
 
void minimize (int pass)
 
void minimizeLink (int x, int y, int dir)
 
 NearestNeighborField (const MaskedImageSP _input, MaskedImageSP _output, int _patchsize)
 
void randomize (void)
 
- Public Member Functions inherited from KisShared
bool deref ()
 
bool ref ()
 
int refCount ()
 
QAtomicInt * sharedWeakReference ()
 

Static Public Member Functions

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)
 

Public Attributes

QList< KoChannelInfo * > channels
 
NNArray_type field
 
QRect imSize
 
MaskedImageSP input
 
quint32 nColors
 
MaskedImageSP output
 
std::vector< float > similarity
 

Private Member Functions

void init_similarity_curve (void)
 
void initialize (void)
 
template<typename T >
randomInt (T range)
 

Private Attributes

int patchSize
 

Additional Inherited Members

- Protected Member Functions inherited from KisShared
 KisShared ()
 
 ~KisShared ()
 

Detailed Description

Definition at line 516 of file kis_inpaint.cpp.

Constructor & Destructor Documentation

◆ NearestNeighborField()

NearestNeighborField::NearestNeighborField ( const MaskedImageSP _input,
MaskedImageSP _output,
int _patchsize )
inline

Definition at line 574 of file kis_inpaint.cpp.

574 : patchSize(_patchsize), input(_input), output(_output)
575 {
576 imSize = input->size();
577 field.resize(boost::extents[imSize.width()][imSize.height()]);
579
580 nColors = input->channelCount(); //only color count, doesn't include alpha channels
581 }
int channelCount(void) const
void init_similarity_curve(void)

References MaskedImage::channelCount(), field, imSize, init_similarity_curve(), input, nColors, and MaskedImage::size().

Member Function Documentation

◆ distance()

int NearestNeighborField::distance ( int x,
int y,
int xp,
int yp )
inline

Definition at line 686 of file kis_inpaint.cpp.

687 {
688 qint64 distance = 0;
689 qint64 wsum = 0;
690 const qint64 ssdmax = nColors * 255 * (qint64)255;
691
692 //for each pixel in the source patch
693 for (int dy = -patchSize; dy <= patchSize; dy++) {
694 for (int dx = -patchSize; dx <= patchSize; dx++) {
695 wsum += ssdmax;
696 int xks = x + dx;
697 int yks = y + dy;
698
699 if (xks < 0 || xks >= input->size().width()) {
700 distance += ssdmax;
701 continue;
702 }
703
704 if (yks < 0 || yks >= input->size().height()) {
705 distance += ssdmax;
706 continue;
707 }
708
709 //cannot use masked pixels as a valid source of information
710 if (input->isMasked(xks, yks)) {
711 distance += ssdmax;
712 continue;
713 }
714
715 //corresponding pixel in target patch
716 int xkt = xp + dx;
717 int ykt = yp + dy;
718 if (xkt < 0 || xkt >= output->size().width()) {
719 distance += ssdmax;
720 continue;
721 }
722 if (ykt < 0 || ykt >= output->size().height()) {
723 distance += ssdmax;
724 continue;
725 }
726
727 //cannot use masked pixels as a valid source of information
728 if (output->isMasked(xkt, ykt)) {
729 distance += ssdmax;
730 continue;
731 }
732
733 //SSD distance between pixels
734 float ssd = input->distance(*input, xks, yks, *output, xkt, ykt);
735 distance += qRound(ssd);
736
737 }
738 }
739
740 if (wsum == 0) {
741 return 0; // sanity check, to avoid undefined behaviour in code below
742 }
743 return qFloor(MAX_DIST * (qreal(distance) / wsum));
744 }
bool isMasked(int x, int y)
std::function< float(const MaskedImage &, int, int, const MaskedImage &, int, int) distance)
int distance(int x, int y, int xp, int yp)
const int MAX_DIST

References distance(), MaskedImage::distance, input, MaskedImage::isMasked(), MAX_DIST, nColors, output, patchSize, and MaskedImage::size().

◆ EM_Step()

void NearestNeighborField::EM_Step ( MaskedImageSP source,
MaskedImageSP target,
int R,
bool upscaled )

◆ ExpectationMaximization()

MaskedImageSP NearestNeighborField::ExpectationMaximization ( KisSharedPtr< NearestNeighborField > TargetToSource,
int level,
int radius,
QList< MaskedImageSP > & pyramid )
static

Definition at line 830 of file kis_inpaint.cpp.

831{
832 int iterEM = std::min(2 * level, 4);
833 int iterNNF = std::min(5, 1 + level);
834
835 MaskedImageSP source = nnf_TargetToSource->output;
836 MaskedImageSP target = nnf_TargetToSource->input;
837 MaskedImageSP newtarget = nullptr;
838
839 //EM loop
840 for (int emloop = 1; emloop <= iterEM; emloop++) {
841 //set the new target as current target
842 if (!newtarget.isNull()) {
843 nnf_TargetToSource->input = newtarget;
844 target = newtarget;
845 newtarget = nullptr;
846 }
847
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;
854 }
855 }
856 }
857
858 //minimize the NNF
859 nnf_TargetToSource->minimize(iterNNF);
860
861 //Now we rebuild the target using best patches from source
862 MaskedImageSP newsource = nullptr;
863 bool upscaled = false;
864
865 // Instead of upsizing the final target, we build the last target from the next level source image
866 // So the final target is less blurry (see "Space-Time Video Completion" - page 5)
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());
872 upscaled = true;
873 } else {
874 newsource = pyramid.at(level);
875 newtarget = target->copy();
876 upscaled = false;
877 }
878 //EM Step
879
880 //EM_Step(newsource, newtarget, radius, upscaled);
881 ExpectationStep(nnf_TargetToSource, newsource, newtarget, upscaled);
882 }
883
884 return newtarget;
885}
KisMagneticGraph::vertex_descriptor target(typename KisMagneticGraph::edge_descriptor e, KisMagneticGraph g)
KisMagneticGraph::vertex_descriptor source(typename KisMagneticGraph::edge_descriptor e, KisMagneticGraph g)
bool isNull() const
void upscale(int newW, int newH)
static void ExpectationStep(KisSharedPtr< NearestNeighborField > nnf, MaskedImageSP source, MaskedImageSP target, bool upscale)

References ExpectationStep(), field, input, KisSharedPtr< T >::isNull(), minimize(), output, MaskedImage::size(), source(), target(), and MaskedImage::upscale().

◆ ExpectationStep()

void NearestNeighborField::ExpectationStep ( KisSharedPtr< NearestNeighborField > nnf,
MaskedImageSP source,
MaskedImageSP target,
bool upscale )
static

Definition at line 888 of file kis_inpaint.cpp.

889{
890 //int*** field = nnf->field;
891 int R = nnf->patchSize;
892 if (upscale)
893 R *= 2;
894
895 int H_nnf = nnf->input->size().height();
896 int W_nnf = nnf->input->size().width();
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();
901
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) {
908 float wsum = 0;
909 pixels.clear();
910 weights.clear();
911
912
913 if (!source->containsMasked(x, y, R + 4) /*&& upscale*/) {
914 //speedup computation by copying parts that are not masked.
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));
918 } else {
919 for (int dx = -R ; dx <= R; ++dx) {
920 for (int dy = -R ; dy <= R ; ++dy) {
921 // xpt,ypt = center pixel of the target patch
922 int xpt = x + dx;
923 int ypt = y + dy;
924
925 int xst, yst;
926 float w;
927
928 if (!upscale) {
929 if (xpt < 0 || xpt >= W_nnf || ypt < 0 || ypt >= H_nnf)
930 continue;
931
932 xst = nnf->field[xpt][ypt].x;
933 yst = nnf->field[xpt][ypt].y;
934 int dp = nnf->field[xpt][ypt].distance;
935 // similarity measure between the two patches
936 w = nnf->similarity[dp];
937
938 } else {
939 if (xpt < 0 || (xpt / 2) >= W_nnf || ypt < 0 || (ypt / 2) >= H_nnf)
940 continue;
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;
944 // similarity measure between the two patches
945 w = nnf->similarity[dp];
946 }
947
948 int xs = xst - dx;
949 int ys = yst - dy;
950
951 if (xs < 0 || xs >= W_source || ys < 0 || ys >= H_source)
952 continue;
953
954 if (source->isMasked(xs, ys))
955 continue;
956
957 pixels.push_back(source->getImagePixel(xs, ys));
958 weights.push_back(w);
959 wsum += w;
960 }
961 }
962
963 if (wsum < 1)
964 continue;
965
966 target->mixColors(pixels, weights, wsum, target->getImagePixel(x, y));
967 }
968 }
969 }
970}
Eigen::Matrix< double, 4, 2 > R
#define upscale(value)
std::vector< float > similarity

References field, input, patchSize, R, similarity, MaskedImage::size(), source(), target(), and upscale.

◆ init_similarity_curve()

void NearestNeighborField::init_similarity_curve ( void )
inlineprivate

Definition at line 545 of file kis_inpaint.cpp.

546 {
547 float s_zero = 0.999;
548 float t_halfmax = 0.10;
549
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;
553
554 similarity.resize(MAX_DIST + 1);
555 for (int i = 0; i < (int)similarity.size(); i++) {
556 float t = (float)i / similarity.size();
557 similarity[i] = 0.5 - 0.5 * std::tanh(coef * (t - t_halfmax));
558 }
559 }

References MAX_DIST, and similarity.

◆ initialize() [1/2]

void NearestNeighborField::initialize ( const NearestNeighborField & nnf)
inline

Definition at line 596 of file kis_inpaint.cpp.

597 {
598 float xscale = qreal(imSize.width()) / nnf.imSize.width();
599 float yscale = qreal(imSize.height()) / nnf.imSize.height();
600
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);
605
606 field[x][y].x = nnf.field[xlow][ylow].x * xscale;
607 field[x][y].y = nnf.field[xlow][ylow].y * yscale;
608 field[x][y].distance = MAX_DIST;
609 }
610 }
611 initialize();
612 }

References field, imSize, initialize(), and MAX_DIST.

◆ initialize() [2/2]

void NearestNeighborField::initialize ( void )
inlineprivate

Definition at line 526 of file kis_inpaint.cpp.

527 {
528 for (int y = 0; y < imSize.height(); y++) {
529 for (int x = 0; x < imSize.width(); x++) {
530 field[x][y].distance = distance(x, y, field[x][y].x, field[x][y].y);
531
532 //if the distance is "infinity", try to find a better link
533 int iter = 0;
534 const int maxretry = 20;
535 while (field[x][y].distance == MAX_DIST && iter < maxretry) {
536 field[x][y].x = randomInt(imSize.width() + 1);
537 field[x][y].y = randomInt(imSize.height() + 1);
538 field[x][y].distance = distance(x, y, field[x][y].x, field[x][y].y);
539 iter++;
540 }
541 }
542 }
543 }

References distance(), field, imSize, MAX_DIST, and randomInt().

◆ minimize()

void NearestNeighborField::minimize ( int pass)
inline

Definition at line 615 of file kis_inpaint.cpp.

616 {
617 int min_x = 0;
618 int min_y = 0;
619 int max_x = imSize.width() - 1;
620 int max_y = imSize.height() - 1;
621
622 for (int i = 0; i < pass; i++) {
623 //scanline order
624 for (int y = min_y; y < max_y; y++)
625 for (int x = min_x; x <= max_x; x++)
626 if (field[x][y].distance > 0)
627 minimizeLink(x, y, 1);
628
629 //reverse scanline order
630 for (int y = max_y; y >= min_y; y--)
631 for (int x = max_x; x >= min_x; x--)
632 if (field[x][y].distance > 0)
633 minimizeLink(x, y, -1);
634 }
635 }
void minimizeLink(int x, int y, int dir)

References distance(), field, imSize, and minimizeLink().

◆ minimizeLink()

void NearestNeighborField::minimizeLink ( int x,
int y,
int dir )
inline

Definition at line 637 of file kis_inpaint.cpp.

638 {
639 int xp, yp, dp;
640
641 //Propagation Left/Right
642 if (x - dir > 0 && x - dir < imSize.width()) {
643 xp = field[x - dir][y].x + dir;
644 yp = field[x - dir][y].y;
645 dp = distance(x, y, xp, yp);
646 if (dp < field[x][y].distance) {
647 field[x][y].x = xp;
648 field[x][y].y = yp;
649 field[x][y].distance = dp;
650 }
651 }
652
653 //Propagation Up/Down
654 if (y - dir > 0 && y - dir < imSize.height()) {
655 xp = field[x][y - dir].x;
656 yp = field[x][y - dir].y + dir;
657 dp = distance(x, y, xp, yp);
658 if (dp < field[x][y].distance) {
659 field[x][y].x = xp;
660 field[x][y].y = yp;
661 field[x][y].distance = dp;
662 }
663 }
664
665 //Random search
666 int wi = std::max(output->size().width(), output->size().height());
667 int xpi = field[x][y].x;
668 int ypi = field[x][y].y;
669 while (wi > 0) {
670 xp = xpi + randomInt(2 * wi) - wi;
671 yp = ypi + randomInt(2 * wi) - wi;
672 xp = std::max(0, std::min(output->size().width() - 1, xp));
673 yp = std::max(0, std::min(output->size().height() - 1, yp));
674
675 dp = distance(x, y, xp, yp);
676 if (dp < field[x][y].distance) {
677 field[x][y].x = xp;
678 field[x][y].y = yp;
679 field[x][y].distance = dp;
680 }
681 wi /= 2;
682 }
683 }

References distance(), field, imSize, output, randomInt(), and MaskedImage::size().

◆ randomInt()

template<typename T >
T NearestNeighborField::randomInt ( T range)
inlineprivate

Definition at line 520 of file kis_inpaint.cpp.

521 {
522 return rand() % range;
523 }

◆ randomize()

void NearestNeighborField::randomize ( void )
inline

Definition at line 583 of file kis_inpaint.cpp.

584 {
585 for (int y = 0; y < imSize.height(); y++) {
586 for (int x = 0; x < imSize.width(); x++) {
587 field[x][y].x = randomInt(imSize.width() + 1);
588 field[x][y].y = randomInt(imSize.height() + 1);
589 field[x][y].distance = MAX_DIST;
590 }
591 }
592 initialize();
593 }

References field, imSize, initialize(), MAX_DIST, and randomInt().

Member Data Documentation

◆ channels

QList<KoChannelInfo *> NearestNeighborField::channels

Definition at line 571 of file kis_inpaint.cpp.

◆ field

NNArray_type NearestNeighborField::field

Definition at line 568 of file kis_inpaint.cpp.

◆ imSize

QRect NearestNeighborField::imSize

Definition at line 567 of file kis_inpaint.cpp.

◆ input

MaskedImageSP NearestNeighborField::input

Definition at line 565 of file kis_inpaint.cpp.

◆ nColors

quint32 NearestNeighborField::nColors

Definition at line 570 of file kis_inpaint.cpp.

◆ output

MaskedImageSP NearestNeighborField::output

Definition at line 566 of file kis_inpaint.cpp.

◆ patchSize

int NearestNeighborField::patchSize
private

Definition at line 563 of file kis_inpaint.cpp.

◆ similarity

std::vector<float> NearestNeighborField::similarity

Definition at line 569 of file kis_inpaint.cpp.


The documentation for this class was generated from the following file: