00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 #ifndef IMAGE_RETINEX_C_DEFINED
00039 #define IMAGE_RETINEX_C_DEFINED
00040
00041 #include "Image/Retinex.H"
00042
00043 #include "Image/Image.H"
00044 #include "Image/ImageSet.H"
00045 #include "Image/MathOps.H"
00046 #include "Image/PyramidOps.H"
00047 #include "Image/Range.H"
00048 #include "Image/ShapeOps.H"
00049 #include "Util/Assert.H"
00050 #include "Util/log.H"
00051 #include "Util/safecopy.H"
00052
00053 #include <vector>
00054
00055
00056 template <class T> static
00057 Image<T> retinexCompareNeighbors(const Image<T>& src,
00058 const Image<T>& radiance,
00059 const Point2D<int> shift,
00060 const T maxi,
00061 const Rectangle& bbox)
00062 {
00063 ASSERT(src.getDims() == radiance.getDims());
00064
00065 Image<T> result(src.getDims(), NO_INIT);
00066
00067 const int w = result.getWidth();
00068 const int h = result.getHeight();
00069
00070 const int offset = shift.i + shift.j * w;
00071
00072 const int top = bbox.top();
00073 const int bottom = bbox.bottomO();
00074 const int left = bbox.left();
00075 const int right = bbox.rightO();
00076
00077
00078
00079 const int wskip = w - (right - left);
00080
00081 typename Image<T>::const_iterator sptr = src.begin() + top * w + bbox.left();
00082 typename Image<T>::const_iterator ritr = radiance.begin() + top * w + bbox.left();
00083 typename Image<T>::iterator dptr = result.beginw() + top * w + bbox.left();
00084
00085 for (int y = top; y < bottom; ++y)
00086 {
00087 for (int x = left; x < right; ++x, ++sptr, ++ritr, ++dptr)
00088 {
00089 T val;
00090
00091 if (y+shift.j < 0 || y+shift.j >= h
00092 || x+shift.i < 0 || x+shift.i >= w)
00093 {
00094 val = sptr[0];
00095 }
00096 else
00097 {
00098 val = sptr[offset] + ritr[0] - ritr[offset];
00099 }
00100
00101 if (val > maxi) val = maxi;
00102
00103 *dptr = T(0.5F * (val + sptr[0]));
00104 }
00105
00106 sptr += wskip;
00107 ritr += wskip;
00108 dptr += wskip;
00109 }
00110
00111 return result;
00112 }
00113
00114
00115 size_t retinexDepth(const Dims& dims)
00116 {
00117 size_t power = 0;
00118
00119 while ((dims.w() >> power) > 1 && (dims.h() >> power) > 1)
00120 ++power;
00121
00122 return power + 1;
00123 }
00124
00125
00126 template <class T>
00127 Image<T> intXYWithPad(const Image<T>& src, const bool padx, const bool pady)
00128 {
00129 ASSERT(src.initialized());
00130
00131 const int w = src.getWidth();
00132 const int h = src.getHeight();
00133
00134 const int w2 = w * 2 + int(padx);
00135 const int h2 = h * 2 + int(pady);
00136
00137 Image<T> result(w2, h2, NO_INIT);
00138
00139 typename Image<T>::const_iterator sptr = src.begin();
00140 typename Image<T>::iterator dptr = result.beginw();
00141 for (int j = 0; j < h; ++j)
00142 {
00143 for (int i = 0; i < w; ++i)
00144 {
00145 *dptr++ = *sptr;
00146 *dptr++ = *sptr;
00147 if (padx && i == w-1)
00148 *dptr++ = *sptr;
00149 ++sptr;
00150 }
00151
00152 safecopy(dptr, dptr - w2, w2);
00153 dptr += w2;
00154 if (pady && j == h-1)
00155 {
00156
00157 safecopy(dptr, dptr - w2, w2);
00158 dptr += w2;
00159 }
00160 }
00161
00162 return result;
00163 }
00164
00165
00166 template <class T>
00167 ImageSet<T> buildPyrRetinexLog(const Image<T>& L,
00168 const size_t depth, const int niter,
00169 const Rectangle& outrect)
00170 {
00171 ASSERT(depth >= 1);
00172 ASSERT(niter >= 1);
00173
00174 const ImageSet<T> radiancePyr = buildPyrLocalAvg2x2(L, depth);
00175
00176 if (radiancePyr[depth - 1].getSize() > 25)
00177 LFATAL("invalid toplevel image size %dx%d",
00178 radiancePyr[depth - 1].getWidth(),
00179 radiancePyr[depth - 1].getHeight());
00180
00181 const Range<T> rng = rangeOf(radiancePyr[0]);
00182
00183 Image<T> OP(radiancePyr[depth - 1].getDims(), NO_INIT);
00184 OP.clear(rng.max());
00185
00186 ImageSet<T> result(depth);
00187
00188 std::vector<Rectangle> bboxes(depth);
00189 bboxes[0] = L.getBounds().getOverlap
00190 (Rectangle::tlbrO(outrect.top() - niter - 1,
00191 outrect.left() - niter - 1,
00192 outrect.bottomO() + niter + 1,
00193 outrect.rightO() + niter + 1));
00194 for (size_t i = 1; i < bboxes.size(); ++i)
00195 {
00196 bboxes[i] = radiancePyr[i].getBounds().getOverlap
00197 (Rectangle::tlbrO(bboxes[i-1].top() / 2 - niter - 1,
00198 bboxes[i-1].left() / 2 - niter - 1,
00199 bboxes[i-1].bottomO() / 2 + niter,
00200 bboxes[i-1].rightO() / 2 + niter));
00201 }
00202
00203 for (size_t i = 0; i < bboxes.size(); ++i)
00204 {
00205 LINFO("pyr[%"ZU"] dims=%dx%d, rect=%dx%d @ (%d,%d)",
00206 i, radiancePyr[i].getWidth(), radiancePyr[i].getHeight(),
00207 bboxes[i].width(), bboxes[i].height(),
00208 bboxes[i].left(), bboxes[i].top());
00209 }
00210
00211 for (int lev = depth - 1; lev >= 0; --lev)
00212 {
00213 const Image<T> radiance = radiancePyr[lev];
00214
00215 ASSERT(OP.getDims() == radiance.getDims());
00216
00217 for (int iter = 0; iter < niter; ++iter)
00218 {
00219 OP = retinexCompareNeighbors(OP, radiance, Point2D<int>( 0, -1), rng.max(), bboxes[lev]);
00220 OP = retinexCompareNeighbors(OP, radiance, Point2D<int>( 1, -1), rng.max(), bboxes[lev]);
00221 OP = retinexCompareNeighbors(OP, radiance, Point2D<int>( 1, 0), rng.max(), bboxes[lev]);
00222 OP = retinexCompareNeighbors(OP, radiance, Point2D<int>( 1, 1), rng.max(), bboxes[lev]);
00223 OP = retinexCompareNeighbors(OP, radiance, Point2D<int>( 0, 1), rng.max(), bboxes[lev]);
00224 OP = retinexCompareNeighbors(OP, radiance, Point2D<int>(-1, 1), rng.max(), bboxes[lev]);
00225 OP = retinexCompareNeighbors(OP, radiance, Point2D<int>(-1, 0), rng.max(), bboxes[lev]);
00226 OP = retinexCompareNeighbors(OP, radiance, Point2D<int>(-1, -1), rng.max(), bboxes[lev]);
00227 }
00228
00229 result[lev] = OP;
00230
00231 if (lev > 0)
00232 {
00233 const int padx = radiancePyr[lev-1].getWidth() - OP.getWidth() * 2;
00234 ASSERT(padx == 0 || padx == 1);
00235 const int pady = radiancePyr[lev-1].getHeight() - OP.getHeight() * 2;
00236 ASSERT(pady == 0 || pady == 1);
00237
00238 LINFO("padx = %d, pady = %d", padx, pady);
00239
00240 if (!padx && !pady)
00241 OP = intXY(OP, true);
00242 else
00243 OP = intXYWithPad(OP, bool(padx), bool(pady));
00244 }
00245 else
00246
00247
00248 OP = Image<T>();
00249 }
00250
00251 return result;
00252 }
00253
00254 template ImageSet<float> buildPyrRetinexLog(const Image<float>&, size_t, int,
00255 const Rectangle&);
00256
00257
00258
00259
00260
00261
00262
00263
00264 #endif // IMAGE_RETINEX_C_DEFINED