00001
00002
00003 #include "jsk_perception/oriented_gradient.hpp"
00004
00005 namespace jsk_perception {
00006
00007
00008
00009
00010 void calcOrientedGradient(cv::Mat& src, cv::Mat& dst) {
00011 int width, height;
00012 cv::Mat gimg;
00013
00014 width = src.cols;
00015 height = src.rows;
00016
00017 cv::cvtColor(src, gimg, CV_BGR2GRAY);
00018
00019 dst.create(height, width, CV_8UC3);
00020 for (int y = 0; y < height; y++) {
00021 for (int x = 0; x < width; x++) {
00022 cv::Vec3b& px=dst.at<cv::Vec3b>(y, x);
00023 for (int k = 0; k < 3; k++) {
00024 px[k] = 0;
00025 }
00026 }
00027 }
00028
00029 float r2 = sqrt(2.0);
00030
00031 for (int y = 1; y < height - 1; y++) {
00032 for (int x = 1; x < width - 1; x++) {
00033 int m,th;
00034 float dx,dy;
00035 float dxx,dyy,dxy,dyx;
00036 double dth;
00037
00038 dxx = (float)gimg.at<unsigned char>(y, x + 1)
00039 - (float)gimg.at<unsigned char>(y, x - 1);
00040 dyy = (float)gimg.at<unsigned char>(y + 1, x)
00041 - (float)gimg.at<unsigned char>(y - 1, x);
00042 dxy = (float)gimg.at<unsigned char>(y + 1, x + 1)
00043 - (float)gimg.at<unsigned char>(y - 1, x - 1);
00044 dyx = (float)gimg.at<unsigned char>(y + 1, x - 1)
00045 - (float)gimg.at<unsigned char>(y - 1, x + 1);
00046
00047 dx = 0.5 * (dxx + 0.5 * r2 * (dxy - dyx));
00048 dy = 0.5 * (dyy + 0.5 * r2 * (dxy + dyx));
00049
00050
00051 m = (int)(sqrt(0.5 * (dx * dx + dy * dy)));
00052
00053 dth = atan2(dy, dx) * 180.0 / M_PI;
00054 if (dth < 0.0) dth += 180.0;
00055 if (dth >= 180.0) dth -= 180.0;
00056 th = (int)dth;
00057
00058 dst.at<cv::Vec3b>(y, x) = cv::Vec3b(th, 255, m);
00059
00060 }
00061 }
00062 }
00063
00064
00065
00066
00067
00068
00069
00070 void calcOGKeyPoints(cv::Mat& src,
00071 cv::Mat& dst,
00072 std::vector<cv::Point>& result,
00073 int thres,
00074 int bs) {
00075 calcOrientedGradient(src, dst);
00076 int width, height;
00077 width = src.cols;
00078 height = src.rows;
00079
00080 result.clear();
00081
00082 for (int y = bs; y < height - bs; y++) {
00083 for (int x = bs; x < width - bs; x++) {
00084 cv::Vec3b& px0 = dst.at<cv::Vec3b>(y, x);
00085 if (px0[2] > thres) {
00086 bool iskey = true;
00087 for (int dx = -bs; dx <= bs; dx++) {
00088 for (int dy = -bs; dy <= bs; dy++) {
00089 if (dx == 0 && dy == 0) break;
00090 cv::Vec3b& px1 = dst.at<cv::Vec3b>(y + dy, x + dx);
00091 if (px0[2] < px1[2]) iskey = false;
00092 }
00093 }
00094 if (iskey) result.push_back(cv::Point(x, y));
00095 }
00096
00097 }
00098 }
00099
00100 }
00101
00102
00103
00104
00105
00106 void calcScaledOrientedGradient(cv::Mat& src, cv::Mat& dst, int scale) {
00107 cv::Mat gimg;
00108 cv::Mat intimg, sqintimg, tintimg;
00109
00110 int width = src.cols;
00111 int height = src.rows;
00112
00113 cv::cvtColor(src, gimg, CV_BGR2GRAY);
00114
00115 dst.create(height, width, CV_8UC3);
00116 unsigned char *gradbuf = dst.ptr();
00117
00118 intimg.create(height + 1, width + 1, CV_32S);
00119 sqintimg.create(height + 1, width + 1, CV_32S);
00120 tintimg.create(height + 1, width + 1, CV_32S);
00121
00122 cv::integral(gimg, intimg, sqintimg, tintimg);
00123
00124 float r2 = sqrt(2.0);
00125 int xidx, idx;
00126 int hscale = scale / 2;
00127 int bsize = hscale * 2 + 1;
00128 int barea0 = scale * scale;
00129 int barea1 = scale * bsize;
00130 int margin = scale;
00131 for (int y = margin; y < height - margin; y++) {
00132 xidx = y * width;
00133 for (int x = margin; x < width - margin; x++) {
00134 int m, th;
00135 float dx, dy;
00136 float dxx, dyy, dxy, dyx;
00137 double dth;
00138
00139 dxx = ((float)(intimg.at<int>(y + hscale + 1, x + scale + 1)
00140 + intimg.at<int>(y - hscale, x + 1)
00141 - intimg.at<int>(y - hscale, x + scale + 1)
00142 - intimg.at<int>(y + hscale + 1, x + 1))
00143 - (float)(intimg.at<int>(y + hscale + 1, x)
00144 +intimg.at<int>(y - hscale, x - scale)
00145 -intimg.at<int>(y - hscale, x)
00146 -intimg.at<int>(y + hscale + 1, x - scale))) / barea1;
00147 dyy = ((float)(intimg.at<int>(y + scale + 1, x + hscale + 1)
00148 + intimg.at<int>(y + 1, x - hscale)
00149 - intimg.at<int>(y + scale + 1, x - hscale)
00150 - intimg.at<int>(y + 1, x + hscale + 1))
00151 - (float)(intimg.at<int>(y - scale, x - hscale)
00152 +intimg.at<int>(y, x + hscale + 1)
00153 -intimg.at<int>(y - scale, x + hscale + 1)
00154 -intimg.at<int>(y, x - hscale))) / barea1;
00155
00156 dxy = ((float)(intimg.at<int>(y + scale + 1, x + scale + 1)
00157 + intimg.at<int>(y + 1, x + 1)
00158 - intimg.at<int>(y + 1, x + scale + 1)
00159 - intimg.at<int>(y + scale + 1, x + 1))
00160 - (float)(intimg.at<int>(y, x)
00161 + intimg.at<int>(y - scale, x - scale)
00162 - intimg.at<int>(y, x - scale)
00163 - intimg.at<int>(y - scale, x))) / barea0;
00164 dyx = ((float)(intimg.at<int>(y + scale + 1, x)
00165 + intimg.at<int>(y + 1, x - scale)
00166 - intimg.at<int>(y + 1, x)
00167 - intimg.at<int>(y + scale + 1, x - scale))
00168 - (float)(intimg.at<int>(y, x + scale + 1)
00169 + intimg.at<int>(y - scale, x + 1)
00170 - intimg.at<int>(y - scale, x + scale + 1)
00171 - intimg.at<int>(y, x + 1))) / barea0;
00172
00173 dx = 0.5 * (dxx + 0.5 * r2 * (dxy - dyx));
00174 dy = 0.5 * (dyy + 0.5 * r2 * (dxy + dyx));
00175
00176 m = (int)(sqrt(0.5 * (dx * dx + dy * dy)));
00177
00178 dth = atan2(dy, dx) * 180.0 / M_PI;
00179 if (dth < 0.0) dth += 180.0;
00180 if (dth >= 180.0) dth -= 180.0;
00181 th = (int)dth;
00182
00183 gradbuf[(xidx + x) * 3] = th;
00184 gradbuf[(xidx + x) * 3 + 1] = 255;
00185 gradbuf[(xidx + x) * 3 + 2] = m;
00186 }
00187 }
00188 }
00189
00190
00191
00192
00193 void calcSOGKeyPoints(cv::Mat& src, cv::Mat& dst) {
00194 cv::Mat gimg;
00195 cv::Mat intimg, sqintimg, tintimg;
00196
00197 int width = src.cols;
00198 int height = src.rows;
00199
00200 std::vector<std::vector<float> > gradimglist;
00201 std::vector<int> scalelist;
00202
00203 cv::cvtColor(src, gimg, CV_BGR2GRAY);
00204
00205 dst.create(height, width, CV_8UC3);
00206 unsigned char *gradbuf = dst.ptr();
00207
00208 intimg.create(height + 1, width + 1, CV_32S);
00209 sqintimg.create(height + 1, width + 1, CV_32S);
00210 tintimg.create(height + 1, width + 1, CV_32S);
00211
00212 cv::integral(gimg, intimg, sqintimg, tintimg);
00213
00214
00215 int maxscale = 10;
00216 scalelist.resize(width * height);
00217
00218
00219 gradimglist.resize((maxscale + 1) * 3);
00220
00221 for(int i = 0; i < gradimglist.size(); i++)
00222 gradimglist[i].resize(width * height);
00223
00224
00225 float r2 = sqrt(2.0);
00226 int xidx, idx;
00227 for (int y = 1; y < height - 1; y++) {
00228 xidx = y * width;
00229 for (int x = 1; x < width - 1; x++) {
00230 float dx, dy;
00231 float dxx, dyy, dxy, dyx;
00232
00233 dxx = (float)gimg.at<unsigned char>(y, x + 1)
00234 - (float)gimg.at<unsigned char>(y, x - 1);
00235 dyy = (float)gimg.at<unsigned char>(y + 1, x)
00236 - (float)gimg.at<unsigned char>(y - 1, x);
00237 dxy = (float)gimg.at<unsigned char>(y + 1, x + 1)
00238 - (float)gimg.at<unsigned char>(y - 1, x - 1);
00239 dyx = (float)gimg.at<unsigned char>(y + 1, x - 1)
00240 - (float)gimg.at<unsigned char>(y - 1, x + 1);
00241
00242 dx = 0.5 * (dxx + 0.5 * r2 * (dxy - dyx));
00243 dy = 0.5 * (dyy + 0.5 * r2 * (dxy + dyx));
00244
00245 idx = xidx + x;
00246 gradimglist[0][idx] = dx * dx + dy * dy;
00247 gradimglist[1][idx] = dx;
00248 gradimglist[2][idx] = dy;
00249 }
00250 }
00251
00252
00253 for (int scale = 2; scale <= maxscale; scale++) {
00254
00255 int hscale = scale / 2;
00256 int bsize = hscale * 2 + 1;
00257 int barea0 = scale * scale;
00258 int barea1 = scale * bsize;
00259 int margin = scale;
00260
00261 int sidx = (scale - 1) * 3;
00262 for (int y = margin; y < height - margin; y++) {
00263 xidx = y * width;
00264 for (int x = margin; x < width - margin; x++) {
00265 float dx, dy;
00266 float dxx, dyy, dxy, dyx;
00267
00268 dxx = ((float)(intimg.at<int>(y + hscale + 1, x + scale + 1)
00269 + intimg.at<int>(y - hscale, x + 1)
00270 - intimg.at<int>(y - hscale, x + scale + 1)
00271 - intimg.at<int>(y + hscale + 1, x + 1))
00272 - (float)(intimg.at<int>(y + hscale + 1, x)
00273 + intimg.at<int>(y - hscale, x - scale)
00274 - intimg.at<int>(y - hscale, x)
00275 - intimg.at<int>(y + hscale + 1, x - scale)))
00276 / barea1;
00277 dyy = ((float)(intimg.at<int>(y + scale + 1, x + hscale + 1)
00278 + intimg.at<int>(y + 1, x - hscale)
00279 - intimg.at<int>(y + scale + 1, x - hscale)
00280 - intimg.at<int>(y + 1, x + hscale + 1))
00281 -(float)(intimg.at<int>(y - scale, x - hscale)
00282 +intimg.at<int>(y, x + hscale + 1)
00283 -intimg.at<int>(y - scale, x + hscale + 1)
00284 -intimg.at<int>(y, x - hscale))) / barea1;
00285
00286
00287 dxy = ((float)(intimg.at<int>(y + scale + 1, x + scale + 1)
00288 + intimg.at<int>(y + 1, x + 1)
00289 - intimg.at<int>(y + 1, x + scale + 1)
00290 - intimg.at<int>(y + scale + 1, x + 1))
00291 - (float)(intimg.at<int>(y, x)
00292 + intimg.at<int>(y - scale, x - scale)
00293 - intimg.at<int>(y, x - scale)
00294 - intimg.at<int>(y - scale, x))) / barea0;
00295 dyx = ((float)(intimg.at<int>(y + scale + 1, x)
00296 + intimg.at<int>(y + 1, x - scale)
00297 - intimg.at<int>(y + 1, x)
00298 - intimg.at<int>(y + scale + 1, x - scale))
00299 - (float)(intimg.at<int>(y, x + scale + 1)
00300 + intimg.at<int>(y - scale, x + 1)
00301 - intimg.at<int>(y - scale, x + scale + 1)
00302 - intimg.at<int>(y, x + 1))) / barea0;
00303
00304 dx = 0.5 * (dxx + 0.5 * r2 * (dxy - dyx));
00305 dy = 0.5 * (dyy + 0.5 * r2 * (dxy + dyx));
00306
00307 idx = xidx + x;
00308 gradimglist[sidx][idx] = dx * dx + dy * dy;
00309 gradimglist[sidx + 1][idx] = dx;
00310 gradimglist[sidx + 2][idx] = dy;
00311 }
00312 }
00313 }
00314
00315
00316 int ofs = 1 + maxscale;
00317 for (int y = ofs; y < height - ofs; y++) {
00318 xidx = y * width;
00319 for (int x = ofs; x < width - ofs; x++) {
00320 idx = xidx + x;
00321 float m, mmax, th;
00322 int sscale = 0;
00323 int mscale = sscale;
00324 float dx, dy;
00325 mmax = gradimglist[sscale][idx];
00326 for (int scale = sscale + 1; scale <= maxscale; scale++) {
00327 m = gradimglist[scale * 3][idx];
00328 if (mmax < m) {
00329 mmax = m;
00330 mscale = scale;
00331 } else {
00332 break;
00333 }
00334 }
00335 m = sqrt(mmax);
00336 dx = gradimglist[mscale * 3 + 1][idx];
00337 dy = gradimglist[mscale * 3 + 2][idx];
00338 th = atan2(dy, dx) * 180.0 / M_PI;
00339 if (th < 0.0) th += 180.0;
00340 if (th >= 180.0) th -= 180.0;
00341 scalelist[idx] = mscale;
00342
00343 gradbuf[idx * 3] = (unsigned char)th;
00344 gradbuf[idx * 3 + 1] = 255;
00345 gradbuf[idx * 3 + 2] = (unsigned char)m;
00346 }
00347 }
00348
00349
00350 for (int y = ofs; y < height - ofs; y++) {
00351 xidx = y * width;
00352 for (int x = ofs; x < width - ofs; x++) {
00353 idx = xidx + x;
00354 int scale = scalelist[idx];
00355 float m = gradimglist[scale][idx];
00356 bool iskey = false;
00357 if (sqrt(m) > 32) {
00358 iskey = true;
00359 for (int sc = scale > 0 ? scale - 1 : 0;
00360 sc < (scale < maxscale ? scale + 1 : maxscale);
00361 sc++) {
00362 for (int xx = -1; xx <= 1; xx++) {
00363 if (m < gradimglist[sc][idx + xx]
00364 || m < gradimglist[sc][idx + xx + width]
00365 || m < gradimglist[sc][idx + xx - width]) {
00366 iskey = false;
00367 break;
00368 }
00369 }
00370 }
00371 }
00372
00373 if (iskey) {
00374 cv::circle(src,
00375 cv::Point(x, y),
00376 scale + 1,
00377 cv::Scalar(0, 0, 255),
00378 1,
00379 4);
00380 } else {
00381
00382
00383
00384 }
00385 }
00386 }
00387 }
00388
00389
00390 }