Non active anchors are now thinner + bugfix + code cleanup
See issue #2239
This commit is contained in:
@@ -9,62 +9,65 @@
|
|||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
width="16px"
|
width="11"
|
||||||
height="16px"
|
height="11"
|
||||||
id="svg2985"
|
id="svg2"
|
||||||
version="1.1"
|
version="1.1"
|
||||||
inkscape:version="0.48.4 r9939"
|
inkscape:version="0.92.3 (2405546, 2018-03-11)"
|
||||||
sodipodi:docname="New document 2">
|
sodipodi:docname="spot-normal.svg">
|
||||||
<defs
|
<defs
|
||||||
id="defs2987" />
|
id="defs4" />
|
||||||
<sodipodi:namedview
|
<sodipodi:namedview
|
||||||
id="base"
|
id="base"
|
||||||
pagecolor="#e43a3a"
|
pagecolor="#a94a4a"
|
||||||
bordercolor="#666666"
|
bordercolor="#666666"
|
||||||
borderopacity="1.0"
|
borderopacity="1.0"
|
||||||
inkscape:pageopacity="0"
|
inkscape:pageopacity="0"
|
||||||
inkscape:pageshadow="2"
|
inkscape:pageshadow="2"
|
||||||
inkscape:zoom="16"
|
inkscape:zoom="22.627417"
|
||||||
inkscape:cx="6.2977477"
|
inkscape:cx="8.1603829"
|
||||||
inkscape:cy="8.0892157"
|
inkscape:cy="7.1741798"
|
||||||
inkscape:current-layer="layer1"
|
|
||||||
showgrid="true"
|
|
||||||
inkscape:grid-bbox="true"
|
|
||||||
inkscape:document-units="px"
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="false"
|
||||||
inkscape:window-width="1920"
|
inkscape:window-width="1920"
|
||||||
inkscape:window-height="1025"
|
inkscape:window-height="1005"
|
||||||
inkscape:window-x="-2"
|
inkscape:window-x="-9"
|
||||||
inkscape:window-y="-3"
|
inkscape:window-y="-9"
|
||||||
inkscape:window-maximized="1" />
|
inkscape:window-maximized="1" />
|
||||||
<metadata
|
<metadata
|
||||||
id="metadata2990">
|
id="metadata7">
|
||||||
<rdf:RDF>
|
<rdf:RDF>
|
||||||
<cc:Work
|
<cc:Work
|
||||||
rdf:about="">
|
rdf:about="">
|
||||||
<dc:format>image/svg+xml</dc:format>
|
<dc:format>image/svg+xml</dc:format>
|
||||||
<dc:type
|
<dc:type
|
||||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
<dc:title></dc:title>
|
<dc:title />
|
||||||
</cc:Work>
|
</cc:Work>
|
||||||
</rdf:RDF>
|
</rdf:RDF>
|
||||||
</metadata>
|
</metadata>
|
||||||
<g
|
<g
|
||||||
id="layer1"
|
|
||||||
inkscape:label="Layer 1"
|
inkscape:label="Layer 1"
|
||||||
inkscape:groupmode="layer">
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(0,-1041.3622)">
|
||||||
<path
|
<path
|
||||||
style="fill:#000000;fill-opacity:1;stroke:none"
|
style="fill:#000000;fill-opacity:0.66666667;stroke:none"
|
||||||
d="M 8 0 C 3.581722 1.1842379e-15 0 3.581722 0 8 C -1.1842379e-15 12.418278 3.581722 16 8 16 C 12.418278 16 16 12.418278 16 8 C 16 3.581722 12.418278 -1.7763568e-15 8 0 z M 8 1.5 C 11.597233 1.5 14.5 4.4027671 14.5 8 C 14.5 11.597233 11.597233 14.5 8 14.5 C 4.4027671 14.5 1.5 11.597233 1.5 8 C 1.5 4.4027671 4.4027671 1.5 8 1.5 z "
|
d="M 6,1043.3622 5.378906,1046.7411 2,1047.3622 v 1 l 3.378906,0.6211 L 6,1052.3622 H 7 L 7.621094,1048.9833 11,1048.3622 v -1 L 7.621094,1046.7411 7,1043.3622 Z"
|
||||||
id="path2993" />
|
id="path818"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
<path
|
<path
|
||||||
sodipodi:type="arc"
|
|
||||||
style="fill:#ffffff;fill-opacity:1;stroke:none"
|
style="fill:#ffffff;fill-opacity:1;stroke:none"
|
||||||
id="path3766"
|
d="m 5,1042.3622 h 1 l 0.8286408,4.5 L 6,1051.3622 H 5 l -0.8286408,-4.5 z"
|
||||||
sodipodi:cx="7.9962873"
|
id="rect2989"
|
||||||
sodipodi:cy="7.9586635"
|
inkscape:connector-curvature="0"
|
||||||
sodipodi:rx="7.9962873"
|
sodipodi:nodetypes="ccccccc" />
|
||||||
sodipodi:ry="7.9962873"
|
<path
|
||||||
d="m 15.992575,7.9586635 a 7.9962873,7.9962873 0 1 1 -15.992575,0 7.9962873,7.9962873 0 1 1 15.992575,0 z"
|
sodipodi:nodetypes="ccccccc"
|
||||||
transform="matrix(0.53285867,0,0,0.53285867,3.7391089,3.7591563)" />
|
inkscape:connector-curvature="0"
|
||||||
|
id="path11"
|
||||||
|
d="m 1,1047.3622 v -1 l 4.5,-0.8286 4.5,0.8286 v 1 l -4.5,0.8286 z"
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:none" />
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.3 KiB |
@@ -623,7 +623,7 @@ void Crop::update(int todo)
|
|||||||
spotsDone = true;
|
spotsDone = true;
|
||||||
PreviewProps pp(trafx, trafy, trafw * skip, trafh * skip, skip);
|
PreviewProps pp(trafx, trafy, trafw * skip, trafh * skip, skip);
|
||||||
//parent->imgsrc->getImage(parent->currWB, tr, origCrop, pp, params.toneCurve, params.raw);
|
//parent->imgsrc->getImage(parent->currWB, tr, origCrop, pp, params.toneCurve, params.raw);
|
||||||
parent->ipf.removeSpots(origCrop, parent->imgsrc, params.spot.entries, pp, parent->currWB, tr);
|
parent->ipf.removeSpots(origCrop, parent->imgsrc, params.spot.entries, pp, parent->currWB, nullptr, tr);
|
||||||
}
|
}
|
||||||
|
|
||||||
DirPyrDenoiseParams denoiseParams = params.dirpyrDenoise;
|
DirPyrDenoiseParams denoiseParams = params.dirpyrDenoise;
|
||||||
@@ -709,7 +709,7 @@ void Crop::update(int todo)
|
|||||||
baseCrop->copyData (spotCrop);
|
baseCrop->copyData (spotCrop);
|
||||||
PreviewProps pp (trafx, trafy, trafw * skip, trafh * skip, skip);
|
PreviewProps pp (trafx, trafy, trafw * skip, trafh * skip, skip);
|
||||||
int tr = getCoarseBitMask(params.coarse);
|
int tr = getCoarseBitMask(params.coarse);
|
||||||
parent->ipf.removeSpots (spotCrop, parent->imgsrc, params.spot.entries, pp, parent->currWB, tr);
|
parent->ipf.removeSpots (spotCrop, parent->imgsrc, params.spot.entries, pp, parent->currWB, ¶ms.icm, tr);
|
||||||
} else {
|
} else {
|
||||||
if (spotCrop) {
|
if (spotCrop) {
|
||||||
delete spotCrop;
|
delete spotCrop;
|
||||||
|
|||||||
@@ -540,7 +540,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange)
|
|||||||
allocCache(spotprev);
|
allocCache(spotprev);
|
||||||
orig_prev->copyData(spotprev);
|
orig_prev->copyData(spotprev);
|
||||||
PreviewProps pp(0, 0, fw, fh, scale);
|
PreviewProps pp(0, 0, fw, fh, scale);
|
||||||
ipf.removeSpots(spotprev, imgsrc, params->spot.entries, pp, currWB, tr);
|
ipf.removeSpots(spotprev, imgsrc, params->spot.entries, pp, currWB, ¶ms->icm, tr);
|
||||||
} else {
|
} else {
|
||||||
if (spotprev) {
|
if (spotprev) {
|
||||||
delete spotprev;
|
delete spotprev;
|
||||||
|
|||||||
@@ -333,7 +333,7 @@ public:
|
|||||||
float MadRgb(const float * DataList, int datalen);
|
float MadRgb(const float * DataList, int datalen);
|
||||||
|
|
||||||
// spot removal tool
|
// spot removal tool
|
||||||
void removeSpots (Imagefloat* img, ImageSource* imgsrc, const std::vector<SpotEntry> &entries, const PreviewProps &pp, const ColorTemp &currWB, int tr);
|
void removeSpots (Imagefloat* img, ImageSource* imgsrc, const std::vector<SpotEntry> &entries, const PreviewProps &pp, const ColorTemp &currWB, const ColorManagementParams *cmp, int tr);
|
||||||
|
|
||||||
// pyramid wavelet
|
// pyramid wavelet
|
||||||
void dirpyr_equalizer(float ** src, float ** dst, int srcwidth, int srcheight, float ** l_a, float ** l_b, const double * mult, const double dirpyrThreshold, const double skinprot, float b_l, float t_l, float t_r, int scale); //Emil's directional pyramid wavelet
|
void dirpyr_equalizer(float ** src, float ** dst, int srcwidth, int srcheight, float ** l_a, float ** l_b, const double * mult, const double dirpyrThreshold, const double skinprot, float b_l, float t_l, float t_r, int scale); //Emil's directional pyramid wavelet
|
||||||
|
|||||||
@@ -785,7 +785,7 @@ private:
|
|||||||
|
|
||||||
// Spot Removal
|
// Spot Removal
|
||||||
if (params.spot.enabled && !params.spot.entries.empty ()) {
|
if (params.spot.enabled && !params.spot.entries.empty ()) {
|
||||||
ipf.removeSpots (baseImg, imgsrc, params.spot.entries, pp, currWB, tr);
|
ipf.removeSpots (baseImg, imgsrc, params.spot.entries, pp, currWB, nullptr, tr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// at this stage, we can flush the raw data to free up quite an important amount of memory
|
// at this stage, we can flush the raw data to free up quite an important amount of memory
|
||||||
|
|||||||
626
rtengine/spot.cc
626
rtengine/spot.cc
@@ -38,34 +38,6 @@ constexpr T skips(T a, T b)
|
|||||||
namespace rtengine
|
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 {
|
class SpotBox {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -329,6 +301,9 @@ public:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define ALGO 1
|
||||||
|
|
||||||
|
#if ALGO==1
|
||||||
bool processIntersectionWith(SpotBox &destBox) {
|
bool processIntersectionWith(SpotBox &destBox) {
|
||||||
Imagefloat *dstImg = destBox.image;
|
Imagefloat *dstImg = destBox.image;
|
||||||
|
|
||||||
@@ -337,30 +312,6 @@ public:
|
|||||||
return false;
|
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 srcImgY = intersectionArea.y1 - imgArea.y1;
|
||||||
int dstImgY = destBox.intersectionArea.y1 - destBox.imgArea.y1;
|
int dstImgY = destBox.intersectionArea.y1 - destBox.imgArea.y1;
|
||||||
for (int y = intersectionArea.y1; y <= intersectionArea.y2; ++y) {
|
for (int y = intersectionArea.y1; y <= intersectionArea.y2; ++y) {
|
||||||
@@ -396,358 +347,44 @@ public:
|
|||||||
|
|
||||||
return true;
|
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
|
#endif
|
||||||
|
|
||||||
int srcImgY = intersection->y1 - imgArea.y1;
|
#if ALGO==2
|
||||||
int dstImgY = intersection->y1 - destBox.imgArea.y1;
|
bool processIntersectionWith(SpotBox &destBox) {
|
||||||
for (int y = intersection->y1; y <= intersection->y2; ++y) {
|
/* The following disabled code has been taken from Gimp 2.8.10 and converted
|
||||||
int srcImgX = intersection->x1 - imgArea.x1;
|
* for RawTherapee by Jean-Christophe FRISCH (aka Hombre) on 02.19.2014.
|
||||||
int dstImgX = intersection->x1 - destBox.imgArea.x1;
|
* 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.
|
||||||
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());
|
|
||||||
|
|
||||||
|
|
||||||
// Destination area
|
/* ORIGINAL NOTES
|
||||||
spp.set(dstSpotBox->imgArea.x1, dstSpotBox->imgArea.y1, dstSpotBox->getImageWidth(),
|
*
|
||||||
dstSpotBox->getImageHeight(), pp.getSkip());
|
* The method used here is similar to the lighting invariant correction
|
||||||
*dstSpotBox /= pp.getSkip();
|
* method but slightly different: we do not divide the RGB components,
|
||||||
dstSpotBox->allocImage();
|
* but substract them I2 = I0 - I1, where I0 is the sample image to be
|
||||||
_image_ = dstSpotBox->getImage();
|
* corrected, I1 is the reference pattern. Then we solve DeltaI=0
|
||||||
for (int y = 0; y < (int)_image_->getHeight(); ++y) {
|
* (Laplace) with I2 Dirichlet conditions at the borders of the
|
||||||
for (int x = 0; x < (int)_image_->getWidth(); ++x) {
|
* mask. The solver is a unoptimized red/black checker Gauss-Siedel
|
||||||
_image_->r(y, x) = 500.f;
|
* with an over-relaxation factor of 1.8. It can benefit from a
|
||||||
_image_->g(y, x) = 500.f;
|
* multi-grid evaluation of an initial solution before the main
|
||||||
_image_->b(y, x) = 60000.f;
|
* iteration loop.
|
||||||
}
|
*
|
||||||
}
|
* I reduced the convergence criteria to 0.1% (0.001) as we are
|
||||||
#ifndef NDEBUG
|
* dealing here with RGB integer components, more is overkill.
|
||||||
printf("~~~~~ Image Size Before : %d, %d\n", _image_->getWidth(), _image_->getHeight());
|
*
|
||||||
#endif
|
* Jean-Yves Couleaud cjyves@free.fr
|
||||||
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 Algorithm Design:
|
||||||
|
*
|
||||||
|
* T. Georgiev, "Photoshop Healing Brush: a Tool for Seamless Cloning
|
||||||
#if 0
|
* http://www.tgeorgiev.net/Photoshop_Healing.pdf
|
||||||
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;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
// ----------------- Core function -----------------
|
// ----------------- Core function -----------------
|
||||||
|
|
||||||
#if 0
|
|
||||||
int scaledPPX = pp.getX() / pp.skip;
|
int scaledPPX = pp.getX() / pp.skip;
|
||||||
int scaledPPY = pp.getY() / pp.skip;
|
int scaledPPY = pp.getY() / pp.skip;
|
||||||
int scaledPPW = pp.getWidth() / pp.skip + (pp.getWidth() % pp.getSkip() > 0);
|
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
|
// repeat until convergence or max iterations
|
||||||
for (int n = 0; n < MAX_ITER; ++n) {
|
for (int n = 0; n < MAX_ITER; ++n) {
|
||||||
|
|
||||||
printf ("<<< n=#%d\n", n);
|
|
||||||
// ----------------------------------------------------------------
|
// ----------------------------------------------------------------
|
||||||
|
|
||||||
/* Perform one iteration of the Laplace solver for matrix. Store the
|
/* 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
|
// do reds
|
||||||
for (i = 0; i < matrix.getHeight(); ++i) {
|
for (i = 0; i < matrix.getHeight(); ++i) {
|
||||||
for (j = i % 2; j < matrix.getWidth(); j += 2) {
|
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))) {
|
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
|
// do nothing at the boundary or outside mask
|
||||||
solution.r (i, j) = matrix.r (i, j);
|
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 (i = 0; i < matrix.getHeight(); i++) {
|
||||||
for (j = (i % 2) ? 0 : 1; j < matrix.getWidth(); j += 2) {
|
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))) {
|
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
|
// do nothing at the boundary or outside mask
|
||||||
solution.r (i, j) = matrix.r (i, j);
|
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) {
|
if (sqr_err_r < EPSILON && sqr_err_g < EPSILON && sqr_err_b < EPSILON) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf ("\n>>> n=#%d\n", n);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
printf ("\n");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// add solution to original image and store in tempPR
|
// add solution to original image and store in tempPR
|
||||||
for (int i = 0, i2 = dst_YMin; i2 < dst_YMax - 1; ++i, ++i2) {
|
for (int i = 0, i2 = dst_YMin; i2 < dst_YMax - 1; ++i, ++i2) {
|
||||||
if (i2 < 0 || i2 >= img->getHeight()) {
|
if (i2 < 0 || i2 >= img->getHeight()) {
|
||||||
@@ -977,25 +601,189 @@ void ImProcFunctions::removeSpots (Imagefloat* img, ImageSource* imgsrc, const s
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
//float c2 = float (mask (i, j)) / 255.f;
|
float c2 = float (mask (i, j)) / 255.f;
|
||||||
//float c1 = 1.f - c2;
|
float c1 = 1.f - c2;
|
||||||
//resultPR->r(i,j) = (unsigned char) CLAMP0255 ( ROUND( double(first->r(i,j)) + double(secondPR->r(i,j)) ) );
|
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;
|
|
||||||
/*
|
|
||||||
img->r(i2,j2) = img->r(i2,j2)*c1 + (solution.r(i,j) + srcBuff->r(i,j))*c2;
|
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->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;
|
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
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user