Non active anchors are now thinner + bugfix + code cleanup

See issue #2239
This commit is contained in:
Hombre
2019-08-15 02:15:26 +02:00
parent 4d4f54cbc2
commit b4d77986a6
6 changed files with 246 additions and 455 deletions

View File

@@ -38,34 +38,6 @@ constexpr T skips(T a, T b)
namespace rtengine
{
/* Code taken from Gimp 2.8.10 and converted for RawTherapee by Jean-Christophe FRISCH (aka Hombre) on 02.19.2014
*
* ORIGINAL NOTES
*
* The method used here is similar to the lighting invariant correction
* method but slightly different: we do not divide the RGB components,
* but substract them I2 = I0 - I1, where I0 is the sample image to be
* corrected, I1 is the reference pattern. Then we solve DeltaI=0
* (Laplace) with I2 Dirichlet conditions at the borders of the
* mask. The solver is a unoptimized red/black checker Gauss-Siedel
* with an over-relaxation factor of 1.8. It can benefit from a
* multi-grid evaluation of an initial solution before the main
* iteration loop.
*
* I reduced the convergence criteria to 0.1% (0.001) as we are
* dealing here with RGB integer components, more is overkill.
*
* Jean-Yves Couleaud cjyves@free.fr
*/
/* Original Algorithm Design:
*
* T. Georgiev, "Photoshop Healing Brush: a Tool for Seamless Cloning
* http://www.tgeorgiev.net/Photoshop_Healing.pdf
*/
#if 1
class SpotBox {
public:
@@ -329,6 +301,9 @@ public:
return true;
}
#define ALGO 1
#if ALGO==1
bool processIntersectionWith(SpotBox &destBox) {
Imagefloat *dstImg = destBox.image;
@@ -337,30 +312,6 @@ public:
return false;
}
/*
printf("#%llu: spotBox(X1:%d, Y1:%d, X2:%d, Y2:%d, W:%d, H:%d) img(W:%d, H:%d)\n", i,
spotArea.x1, spotArea.y1, spotArea.x2, spotArea.y2,
getWidth(), getHeight(),
destBox.getWidth(), destBox.getHeight()
);
*/
#ifndef NDEBUG
printf("[processIntersectionWith] srcSpotBox @ %p(%d, %d) - img @ %p(%d, %d) / dstSpotBox @ %p(%d, %d) - img @ %p(%d, %d)\n",
this, getWidth(), getHeight(), image, destBox.getWidth(), destBox.getHeight(),
&destBox, destBox.getWidth(), destBox.getHeight(), destBox.image, dstImg->getWidth(), dstImg->getHeight());
printf(" [spot] srcSpotBox (%d, %d) -> (%d, %d) / dstSpotBox (%d, %d) -> (%d, %d)\n",
spotArea.x1, spotArea.y1, spotArea.x2, spotArea.y2,
destBox.spotArea.x1, destBox.spotArea.y1, destBox.spotArea.x2, destBox.spotArea.y2);
printf(" [img ] srcSpotBox (%d, %d) -> (%d, %d) / dstSpotBox (%d, %d) -> (%d, %d)\n",
imgArea.x1, imgArea.y1, imgArea.x2, imgArea.y2,
destBox.imgArea.x1, destBox.imgArea.y1, destBox.imgArea.x2, destBox.imgArea.y2);
printf(" [intr] srcSpotBox (%d, %d) -> (%d, %d) / dstSpotBox (%d, %d) -> (%d, %d)\n",
intersectionArea.x1, intersectionArea.y1, intersectionArea.x2, intersectionArea.y2,
destBox.intersectionArea.x1, destBox.intersectionArea.y1, destBox.intersectionArea.x2, destBox.intersectionArea.y2);
printf(" radius = %.3f\n", radius);
#endif
int srcImgY = intersectionArea.y1 - imgArea.y1;
int dstImgY = destBox.intersectionArea.y1 - destBox.imgArea.y1;
for (int y = intersectionArea.y1; y <= intersectionArea.y2; ++y) {
@@ -396,358 +347,44 @@ public:
return true;
}
// Copy the intersecting part
bool copyImgTo(SpotBox &destBox) {
Imagefloat *destImg = destBox.image;
if (image == nullptr || destImg == nullptr) {
std::cerr << "One of the source or destination SpotBox image is missing !" << std::endl;
return false;
}
/*
printf("#%llu: spotBox(X1:%d, Y1:%d, X2:%d, Y2:%d, W:%d, H:%d) img(W:%d, H:%d)\n", i,
spotArea.x1, spotArea.y1, spotArea.x2, spotArea.y2,
getWidth(), getHeight(),
destBox.getWidth(), destBox.getHeight()
);
*/
std::unique_ptr<Rectangle> intersection;
if (!intersectionArea.getIntersection(destBox.intersectionArea, intersection)) {
return false;
}
Imagefloat *srcImg = image;
Imagefloat *dstImg = destBox.image;
#ifndef NDEBUG
printf("[copyImgTo] srcSpotBox @ %p(%d, %d) - img @ %p(%d, %d) / dstSpotBox @ %p(%d, %d) - img @ %p(%d, %d)\n",
this, getWidth(), getHeight(), image, srcImg->getWidth(), srcImg->getHeight(),
&destBox, destBox.getWidth(), destBox.getHeight(), destBox.image, dstImg->getWidth(), dstImg->getHeight());
printf(" [spot] srcSpotBox (%d, %d) -> (%d, %d) / dstSpotBox (%d, %d) -> (%d, %d)\n",
spotArea.x1, spotArea.y1, spotArea.x2, spotArea.y2,
destBox.spotArea.x1, destBox.spotArea.y1, destBox.spotArea.x2, destBox.spotArea.y2);
printf(" [img ] srcSpotBox (%d, %d) -> (%d, %d) / dstSpotBox (%d, %d) -> (%d, %d)\n",
imgArea.x1, imgArea.y1, imgArea.x2, imgArea.y2,
destBox.imgArea.x1, destBox.imgArea.y1, destBox.imgArea.x2, destBox.imgArea.y2);
printf(" [intr] intersection (%d, %d) -> (%d, %d)\n",
intersection->x1, intersection->y1, intersection->x2, intersection->y2);
#endif
int srcImgY = intersection->y1 - imgArea.y1;
int dstImgY = intersection->y1 - destBox.imgArea.y1;
for (int y = intersection->y1; y <= intersection->y2; ++y) {
int srcImgX = intersection->x1 - imgArea.x1;
int dstImgX = intersection->x1 - destBox.imgArea.x1;
for (int x = intersection->x1; x <= intersection->x2; ++x) {
dstImg->r(dstImgY, dstImgX) = srcImg->r(srcImgY, srcImgX);
dstImg->g(dstImgY, dstImgX) = srcImg->g(srcImgY, srcImgX);
dstImg->b(dstImgY, dstImgX) = srcImg->b(srcImgY, srcImgX);
++srcImgX;
++dstImgX;
}
++srcImgY;
++dstImgY;
}
return true;
}
};
void ImProcFunctions::removeSpots (Imagefloat* img, ImageSource* imgsrc, const std::vector<SpotEntry> &entries, const PreviewProps &pp, const ColorTemp &currWB, int tr)
{
//Get the clipped image areas (src & dst) from the source image
std::vector< std::shared_ptr<SpotBox> > srcSpotBoxs;
std::vector< std::shared_ptr<SpotBox> > dstSpotBoxs;
int fullImgWidth = 0;
int fullImgHeight = 0;
imgsrc->getFullSize(fullImgWidth, fullImgHeight, tr);
SpotBox fullImageBox(0, 0, fullImgWidth - 1, fullImgHeight - 1, 0, 0, nullptr, SpotBox::Type::FINAL);
SpotBox cropBox(pp.getX(), pp.getY(),
pp.getX() + pp.getWidth() - 1, pp.getY() + pp.getHeight() - 1,
0, 0, img, SpotBox::Type::FINAL);
std::set<int> visibleSpots; // list of dest spots intersecting the preview's crop
int i = 0;
for (auto entry : params->spot.entries) {
std::shared_ptr<SpotBox> srcSpotBox(new SpotBox(entry, SpotBox::Type::SOURCE));
std::shared_ptr<SpotBox> dstSpotBox(new SpotBox(entry, SpotBox::Type::TARGET));
if ( !srcSpotBox->setIntersectionWith(fullImageBox)
|| !dstSpotBox->setIntersectionWith(fullImageBox)
|| !srcSpotBox->imageIntersects(*dstSpotBox, true))
{
continue;
++i;
}
// If spot intersect the preview image, add it to the visible spots
if (dstSpotBox->spotIntersects(cropBox)) {
#ifndef NDEBUG
printf("Spot visible insere: %d\n", i);
#endif
visibleSpots.insert(i);
}
++i;
// Source area
PreviewProps spp(srcSpotBox->imgArea.x1, srcSpotBox->imgArea.y1,
srcSpotBox->getImageWidth(), srcSpotBox->getImageHeight(), pp.getSkip());
int w = 0;
int h = 0;
imgsrc->getSize(spp, w, h);
*srcSpotBox /= pp.getSkip();
srcSpotBox->allocImage();
Imagefloat *_image_ = srcSpotBox->getImage();
for (int y = 0; y < (int)_image_->getHeight(); ++y) {
for (int x = 0; x < (int)_image_->getWidth(); ++x) {
_image_->r(y, x) = 60000.f;
_image_->g(y, x) = 500.f;
_image_->b(y, x) = 500.f;
}
}
#ifndef NDEBUG
printf("~~~~~ Image Size Before : %d, %d\n", _image_->getWidth(), _image_->getHeight());
#endif
imgsrc->getImage(currWB, tr, srcSpotBox->getImage(), spp, params->toneCurve, params->raw);
#ifndef NDEBUG
printf("~~~~~ Image Size After : %d, %d\n", _image_->getWidth(), _image_->getHeight());
#endif
assert(srcSpotBox->checkImageSize());
//printf(" / src size: %d,%d", currSrcSpot->getWidth(), currSrcSpot->getHeight());
#if ALGO==2
bool processIntersectionWith(SpotBox &destBox) {
/* The following disabled code has been taken from Gimp 2.8.10 and converted
* for RawTherapee by Jean-Christophe FRISCH (aka Hombre) on 02.19.2014.
* It has not been tested, at all, an can (does) contain bugs. Feel free to
* replace the actual working code by this one, if results are better.
*/
// Destination area
spp.set(dstSpotBox->imgArea.x1, dstSpotBox->imgArea.y1, dstSpotBox->getImageWidth(),
dstSpotBox->getImageHeight(), pp.getSkip());
*dstSpotBox /= pp.getSkip();
dstSpotBox->allocImage();
_image_ = dstSpotBox->getImage();
for (int y = 0; y < (int)_image_->getHeight(); ++y) {
for (int x = 0; x < (int)_image_->getWidth(); ++x) {
_image_->r(y, x) = 500.f;
_image_->g(y, x) = 500.f;
_image_->b(y, x) = 60000.f;
}
}
#ifndef NDEBUG
printf("~~~~~ Image Size Before : %d, %d\n", _image_->getWidth(), _image_->getHeight());
#endif
imgsrc->getImage(currWB, tr, dstSpotBox->getImage(), spp, params->toneCurve, params->raw);
#ifndef NDEBUG
printf("~~~~~ Image Size After : %d, %d\n", _image_->getWidth(), _image_->getHeight());
#endif
assert(dstSpotBox->checkImageSize());
//printf(" / src size: %d,%d", currDstSpot->getWidth(), currDstSpot->getHeight());
// Update the intersectionArea between src and dest
if (srcSpotBox->mutuallyClipImageArea(*dstSpotBox)) {
srcSpotBoxs.push_back(srcSpotBox);
dstSpotBoxs.push_back(dstSpotBox);
#ifndef NDEBUG
printf("Taille de l'image pour spot #%d: src(%d, %d) / dst(%d, %d)\n", i-1,
srcSpotBox->getImageWidth(), srcSpotBox->getImageHeight(),
dstSpotBox->getImageWidth(), dstSpotBox->getImageHeight()
);
#endif
}
}
// Construct list of upstream dependancies
std::set<int> requiredSpots = visibleSpots; // starting point, visible spots are necessarilly required spots
#ifndef NDEBUG
printf("Required spots: ");
#endif
for (auto i = requiredSpots.rbegin(); i != requiredSpots.rend(); i++) {
int spotNbr = *i;
#ifndef NDEBUG
printf("%d ", spotNbr);
#endif
requiredSpots.insert(spotNbr);
if (spotNbr > 0) {
for (int j = spotNbr - 1; j >= 0; --j) {
if ((srcSpotBoxs.at(spotNbr))->imageIntersects(*dstSpotBoxs.at(j))) {
requiredSpots.insert(spotNbr);
#ifndef NDEBUG
printf("%d ", spotNbr);
#endif
}
}
}
}
#ifndef NDEBUG
printf("\n");
#endif
// Process spots and copy them downstream
for (auto i = requiredSpots.begin(); i != requiredSpots.end(); i++) {
// Process
#ifndef NDEBUG
printf("========>>> Processing spot #%d\n", *i);
#endif
srcSpotBoxs.at(*i)->processIntersectionWith(*dstSpotBoxs.at(*i));
// Propagate
std::set<int> positiveSpots; // For DEBUG purpose only !
auto j = i;
++j;
while (j != requiredSpots.end()) {
bool intersectionFound = false;
int i_ = *i;
int j_ = *j;
#ifndef NDEBUG
printf("Propagating to SRC #%d ?\n", j_);
#endif
intersectionFound |= dstSpotBoxs.at(i_)->copyImgTo(*srcSpotBoxs.at(j_));
#ifndef NDEBUG
printf("Propagating to DSTC #%d ?\n", j_);
#endif
intersectionFound |= dstSpotBoxs.at(i_)->copyImgTo(*dstSpotBoxs.at(j_));
if (intersectionFound) {
positiveSpots.insert(j_);
}
++j;
}
#ifndef NDEBUG
printf("||| DEST spot #%d propagated to : ", *i);
for (auto g : positiveSpots) {
printf("%d ", g);
}
printf("\n");
#endif
}
// Copy the dest spot to the preview image
#ifndef NDEBUG
printf("cropBox (%d, %d) -> (%d, %d)",
cropBox.imgArea.x1, cropBox.imgArea.y1,
cropBox.imgArea.x2, cropBox.imgArea.y2);
#endif
cropBox /= pp.getSkip();
#ifndef NDEBUG
printf(" -> [/skip] (%d, %d) -> (%d, %d)",
cropBox.imgArea.x1, cropBox.imgArea.y1,
cropBox.imgArea.x2, cropBox.imgArea.y2);
#endif
cropBox.tuneImageSize();
cropBox.intersectionArea = cropBox.imgArea;
#ifndef NDEBUG
printf(" -> [/tuned] (%d, %d) -> (%d, %d)\n",
cropBox.imgArea.x1, cropBox.imgArea.y1,
cropBox.imgArea.x2, cropBox.imgArea.y2);
#endif
int f = 0;
for (auto i : visibleSpots) {
f += dstSpotBoxs.at(i)->copyImgTo(cropBox) ? 1 : 0;
}
#ifndef NDEBUG
printf("Nombre de copie finale : %d\n", f);
#endif
/*
printf("#--: spotBox(X1:%d, Y1:%d, X2:%d, Y2:%d, W:%d, H:%d) img(W:%d, H:%d)\n\n",
cropBox.spotArea.x1, cropBox.spotArea.y1, cropBox.spotArea.x2, cropBox.spotArea.y2,
cropBox.getWidth(), cropBox.getHeight(),
cropBox.image->getWidth(), cropBox.image->getHeight()
);
*/
}
#endif
/* ORIGINAL NOTES
*
* The method used here is similar to the lighting invariant correction
* method but slightly different: we do not divide the RGB components,
* but substract them I2 = I0 - I1, where I0 is the sample image to be
* corrected, I1 is the reference pattern. Then we solve DeltaI=0
* (Laplace) with I2 Dirichlet conditions at the borders of the
* mask. The solver is a unoptimized red/black checker Gauss-Siedel
* with an over-relaxation factor of 1.8. It can benefit from a
* multi-grid evaluation of an initial solution before the main
* iteration loop.
*
* I reduced the convergence criteria to 0.1% (0.001) as we are
* dealing here with RGB integer components, more is overkill.
*
* Jean-Yves Couleaud cjyves@free.fr
*/
#if 0
void ImProcFunctions::removeSpots (Imagefloat* img, ImageSource* imgsrc, const std::vector<SpotEntry> &entries, const PreviewProps &pp, const ColorTemp &currWB, int tr)
{
Alpha mask;
for (const auto entry : entries) {
float featherRadius = entry.getFeatherRadius();
int scaledFeatherRadius = featherRadius / pp.getSkip ();
SpotBox srcBox(entry, SpotBox::Type::SOURCE);
srcBox.translate(-pp.getX(), -pp.getY());
srcBox /= float (pp.getSkip());
SpotBox dstBox(entry, SpotBox::Type::TARGET);
dstBox.translate(-pp.getX(), -pp.getY());
dstBox /= float (pp.getSkip());
//printf(" -> X: %04d > %04d\n -> Y: %04d > %04d\n", dst_XMin, dst_XMax, dst_YMin, dst_YMax);
// scaled spot is too small, we do not preview it
if (scaledFeatherRadius < 2 && pp.getSkip() != 1) {
#ifndef NDEBUG
if (options.rtSettings.verbose) {
printf ("Skipping spot located at %d x %d, too small for the preview zoom rate\n", entry.sourcePos.x, entry.sourcePos.y);
}
#endif
continue;
}
// skipping entries totally transparent
if (entry.opacity == 0.) {
#ifndef NDEBUG
if (options.rtSettings.verbose) {
printf ("Skipping spot located at %d x %d: opacity=%.3f\n", entry.sourcePos.x, entry.sourcePos.y, entry.opacity);
}
continue;
#endif
}
// skipping entries where the source circle isn't inside the image bounds, even partially
if (src_XMin < 0 || src_XMax >= img->getWidth() || src_YMin < 0 || src_YMax >= img->getHeight()) {
#ifndef NDEBUG
if (options.rtSettings.verbose) {
printf ("Skipping spot located at %d x %d, from the data at %d x %d, radius=%d, feather=%.3f, opacity=%.3f: source out of bounds\n", entry.sourcePos.x, entry.sourcePos.y, entry.targetPos.x, entry.targetPos.y, entry.radius, entry.feather, entry.opacity);
printf ("%d < 0 || %d >= %d || %d < 0 || %d >= %d\n",
src_XMin, src_XMax, img->getWidth(), src_YMin, src_YMax, img->getHeight());
}
#endif
continue;
}
// skipping entries where the dest circle is completely outside the image bounds
/*
if (dst_XMin >= img->getWidth() || dst_XMax <= 0 || dst_YMin >= img->getHeight() || dst_YMax <= 0) {
#ifndef NDEBUG
if (options.rtSettings.verbose) {
printf ("Skipping spot located at %d x %d, from the data at %d x %d, radius=%d, feather=%.3f, opacity=%.3f: source out of bounds\n", entry.sourcePos.x, entry.sourcePos.y, entry.targetPos.x, entry.targetPos.y, entry.radius, entry.feather, entry.opacity);
printf ("%d >= %d || %d <= 0 || %d >= %d || %d <= 0\n",
dst_XMin, img->getWidth(), dst_XMax, dst_YMin, img->getHeight(), dst_YMax);
}
#endif
continue;
}
*/
/* Original Algorithm Design:
*
* T. Georgiev, "Photoshop Healing Brush: a Tool for Seamless Cloning
* http://www.tgeorgiev.net/Photoshop_Healing.pdf
*/
// ----------------- Core function -----------------
#if 0
int scaledPPX = pp.getX() / pp.skip;
int scaledPPY = pp.getY() / pp.skip;
int scaledPPW = pp.getWidth() / pp.skip + (pp.getWidth() % pp.getSkip() > 0);
@@ -810,7 +447,6 @@ void ImProcFunctions::removeSpots (Imagefloat* img, ImageSource* imgsrc, const s
// repeat until convergence or max iterations
for (int n = 0; n < MAX_ITER; ++n) {
printf ("<<< n=#%d\n", n);
// ----------------------------------------------------------------
/* Perform one iteration of the Laplace solver for matrix. Store the
@@ -829,8 +465,6 @@ void ImProcFunctions::removeSpots (Imagefloat* img, ImageSource* imgsrc, const s
// do reds
for (i = 0; i < matrix.getHeight(); ++i) {
for (j = i % 2; j < matrix.getWidth(); j += 2) {
printf ("/%d,%d", j, i);
if ((0 == mask (i, j)) || (i == 0) || (i == (matrix.getHeight() - 1)) || (j == 0) || (j == (matrix.getWidth() - 1))) {
// do nothing at the boundary or outside mask
solution.r (i, j) = matrix.r (i, j);
@@ -893,8 +527,6 @@ void ImProcFunctions::removeSpots (Imagefloat* img, ImageSource* imgsrc, const s
*/
for (i = 0; i < matrix.getHeight(); i++) {
for (j = (i % 2) ? 0 : 1; j < matrix.getWidth(); j += 2) {
printf (":%d,%d", j, i);
if ((0 == mask (i, j)) || (i == 0) || (i == (matrix.getHeight() - 1)) || (j == 0) || (j == (matrix.getWidth() - 1))) {
// do nothing at the boundary or outside mask
solution.r (i, j) = matrix.r (i, j);
@@ -956,16 +588,8 @@ void ImProcFunctions::removeSpots (Imagefloat* img, ImageSource* imgsrc, const s
if (sqr_err_r < EPSILON && sqr_err_g < EPSILON && sqr_err_b < EPSILON) {
break;
}
printf ("\n>>> n=#%d\n", n);
}
printf ("\n");
#endif
// add solution to original image and store in tempPR
for (int i = 0, i2 = dst_YMin; i2 < dst_YMax - 1; ++i, ++i2) {
if (i2 < 0 || i2 >= img->getHeight()) {
@@ -977,25 +601,189 @@ void ImProcFunctions::removeSpots (Imagefloat* img, ImageSource* imgsrc, const s
continue;
}
//float c2 = float (mask (i, j)) / 255.f;
//float c1 = 1.f - c2;
//resultPR->r(i,j) = (unsigned char) CLAMP0255 ( ROUND( double(first->r(i,j)) + double(secondPR->r(i,j)) ) );
img->r (i2, j2) = 65535.0f; //img->r(i2,j2)*c1 + srcBuff->r(i,j)*c2;
img->g (i2, j2) = 0.0f; //img->g(i2,j2)*c1 + srcBuff->g(i,j)*c2;
img->b (i2, j2) = 0.0f; //img->b(i2,j2)*c1 + srcBuff->b(i,j)*c2;
/*
float c2 = float (mask (i, j)) / 255.f;
float c1 = 1.f - c2;
resultPR->r(i,j) = (unsigned char) CLAMP0255 ( ROUND( double(first->r(i,j)) + double(secondPR->r(i,j)) ) );
img->r(i2,j2) = img->r(i2,j2)*c1 + (solution.r(i,j) + srcBuff->r(i,j))*c2;
img->g(i2,j2) = img->g(i2,j2)*c1 + (solution.g(i,j) + srcBuff->g(i,j))*c2;
img->b(i2,j2) = img->b(i2,j2)*c1 + (solution.b(i,j) + srcBuff->b(i,j))*c2;
*/
}
}
}
#endif
// Copy the intersecting part
bool copyImgTo(SpotBox &destBox) {
Imagefloat *destImg = destBox.image;
if (image == nullptr || destImg == nullptr) {
std::cerr << "One of the source or destination SpotBox image is missing !" << std::endl;
return false;
}
std::unique_ptr<Rectangle> intersection;
if (!intersectionArea.getIntersection(destBox.intersectionArea, intersection)) {
return false;
}
Imagefloat *srcImg = image;
Imagefloat *dstImg = destBox.image;
int srcImgY = intersection->y1 - imgArea.y1;
int dstImgY = intersection->y1 - destBox.imgArea.y1;
for (int y = intersection->y1; y <= intersection->y2; ++y) {
int srcImgX = intersection->x1 - imgArea.x1;
int dstImgX = intersection->x1 - destBox.imgArea.x1;
for (int x = intersection->x1; x <= intersection->x2; ++x) {
dstImg->r(dstImgY, dstImgX) = srcImg->r(srcImgY, srcImgX);
dstImg->g(dstImgY, dstImgX) = srcImg->g(srcImgY, srcImgX);
dstImg->b(dstImgY, dstImgX) = srcImg->b(srcImgY, srcImgX);
++srcImgX;
++dstImgX;
}
++srcImgY;
++dstImgY;
}
return true;
}
};
void ImProcFunctions::removeSpots (Imagefloat* img, ImageSource* imgsrc, const std::vector<SpotEntry> &entries, const PreviewProps &pp, const ColorTemp &currWB, const ColorManagementParams *cmp, int tr)
{
//Get the clipped image areas (src & dst) from the source image
std::vector< std::shared_ptr<SpotBox> > srcSpotBoxs;
std::vector< std::shared_ptr<SpotBox> > dstSpotBoxs;
int fullImgWidth = 0;
int fullImgHeight = 0;
imgsrc->getFullSize(fullImgWidth, fullImgHeight, tr);
SpotBox fullImageBox(0, 0, fullImgWidth - 1, fullImgHeight - 1, 0, 0, nullptr, SpotBox::Type::FINAL);
SpotBox cropBox(pp.getX(), pp.getY(),
pp.getX() + pp.getWidth() - 1, pp.getY() + pp.getHeight() - 1,
0, 0, img, SpotBox::Type::FINAL);
std::set<int> visibleSpots; // list of dest spots intersecting the preview's crop
int i = 0;
for (auto entry : params->spot.entries) {
std::shared_ptr<SpotBox> srcSpotBox(new SpotBox(entry, SpotBox::Type::SOURCE));
std::shared_ptr<SpotBox> dstSpotBox(new SpotBox(entry, SpotBox::Type::TARGET));
if ( !srcSpotBox->setIntersectionWith(fullImageBox)
|| !dstSpotBox->setIntersectionWith(fullImageBox)
|| !srcSpotBox->imageIntersects(*dstSpotBox, true))
{
continue;
++i;
}
// If spot intersect the preview image, add it to the visible spots
if (dstSpotBox->spotIntersects(cropBox)) {
visibleSpots.insert(i);
}
++i;
// Source area
PreviewProps spp(srcSpotBox->imgArea.x1, srcSpotBox->imgArea.y1,
srcSpotBox->getImageWidth(), srcSpotBox->getImageHeight(), pp.getSkip());
int w = 0;
int h = 0;
imgsrc->getSize(spp, w, h);
*srcSpotBox /= pp.getSkip();
srcSpotBox->allocImage();
Imagefloat *srcImage = srcSpotBox->getImage();
for (int y = 0; y < (int)srcImage->getHeight(); ++y) {
for (int x = 0; x < (int)srcImage->getWidth(); ++x) {
srcImage->r(y, x) = 60000.f;
srcImage->g(y, x) = 500.f;
srcImage->b(y, x) = 500.f;
}
}
imgsrc->getImage(currWB, tr, srcSpotBox->getImage(), spp, params->toneCurve, params->raw);
if (cmp) {
imgsrc->convertColorSpace(srcImage, *cmp, currWB);
}
assert(srcSpotBox->checkImageSize());
// Destination area
spp.set(dstSpotBox->imgArea.x1, dstSpotBox->imgArea.y1, dstSpotBox->getImageWidth(),
dstSpotBox->getImageHeight(), pp.getSkip());
*dstSpotBox /= pp.getSkip();
dstSpotBox->allocImage();
Imagefloat *dstImage = dstSpotBox->getImage();
for (int y = 0; y < (int)dstImage->getHeight(); ++y) {
for (int x = 0; x < (int)dstImage->getWidth(); ++x) {
dstImage->r(y, x) = 500.f;
dstImage->g(y, x) = 500.f;
dstImage->b(y, x) = 60000.f;
}
}
imgsrc->getImage(currWB, tr, dstSpotBox->getImage(), spp, params->toneCurve, params->raw);
if (cmp) {
imgsrc->convertColorSpace(dstImage, *cmp, currWB);
}
assert(dstSpotBox->checkImageSize());
// Update the intersectionArea between src and dest
if (srcSpotBox->mutuallyClipImageArea(*dstSpotBox)) {
srcSpotBoxs.push_back(srcSpotBox);
dstSpotBoxs.push_back(dstSpotBox);
}
}
// Construct list of upstream dependancies
std::set<int> requiredSpots = visibleSpots; // starting point, visible spots are necessarilly required spots
for (auto i = requiredSpots.rbegin(); i != requiredSpots.rend(); i++) {
int spotNbr = *i;
requiredSpots.insert(spotNbr);
if (spotNbr > 0) {
for (int j = spotNbr - 1; j >= 0; --j) {
if ((srcSpotBoxs.at(spotNbr))->imageIntersects(*dstSpotBoxs.at(j))) {
requiredSpots.insert(spotNbr);
}
}
}
}
// Process spots and copy them downstream
for (auto i = requiredSpots.begin(); i != requiredSpots.end(); i++) {
// Process
srcSpotBoxs.at(*i)->processIntersectionWith(*dstSpotBoxs.at(*i));
// Propagate
std::set<int> positiveSpots; // For DEBUG purpose only !
auto j = i;
++j;
while (j != requiredSpots.end()) {
bool intersectionFound = false;
int i_ = *i;
int j_ = *j;
intersectionFound |= dstSpotBoxs.at(i_)->copyImgTo(*srcSpotBoxs.at(j_));
intersectionFound |= dstSpotBoxs.at(i_)->copyImgTo(*dstSpotBoxs.at(j_));
if (intersectionFound) {
positiveSpots.insert(j_);
}
++j;
}
}
// Copy the dest spot to the preview image
cropBox /= pp.getSkip();
cropBox.tuneImageSize();
cropBox.intersectionArea = cropBox.imgArea;
int f = 0;
for (auto i : visibleSpots) {
f += dstSpotBoxs.at(i)->copyImgTo(cropBox) ? 1 : 0;
}
}
#endif
}