Go to the documentation of this file.00001 #include <face_contour_detector/ImageForest.h>
00002
00003 #include <map>
00004 #include <vector>
00005 #include <limits>
00006 #include <face_contour_detector/Bgr8.h>
00007 #include <ros/assert.h>
00008
00009 namespace face_contour_detector {
00010
00011 ImageForest::Point::Point(int x, int y) : x(x), y(y) { }
00012 ImageForest::Point::Point(const Point& other) : x(other.x), y(other.y) { }
00013
00014 ImageForest::Graph::Graph(): id(0), numPixels(0) {}
00015 ImageForest::Graph::Graph(const Graph& other): id(other.id), numPixels(other.numPixels), endPoints(other.endPoints), connectingPoints(other.connectingPoints) {}
00016
00017 ImageForest::ImageForest() : m_width(0), m_height(0), m_lastId(0), m_values(0) {
00018
00019 }
00020
00021 ImageForest::ImageForest(const cv::Mat& mat, unsigned char threshold) : m_width(0), m_height(0), m_lastId(0), m_values(0) {
00022 ReadFromImage(mat, threshold);
00023 }
00024
00025 ImageForest::~ImageForest() {
00026 delete [] m_values;
00027 }
00028
00029 void ImageForest::ReadFromImage(const cv::Mat& mat, unsigned char threshold) {
00030 assert (mat.cols > 0 && mat.rows > 0);
00031 m_width = mat.cols;
00032 m_height = mat.rows;
00033 if (m_values != 0) {
00034 delete [] m_values;
00035 }
00036 m_lastId = 0;
00037
00038 m_values = new int[m_width * m_height];
00039
00040
00041 for (int y = 0; y < m_height; y++) {
00042 for(int x = 0; x < m_width; x++) {
00043 ROS_ASSERT(y*m_width + x < m_height*m_width);
00044 m_values[y*m_width + x] = 0;
00045 }
00046 }
00047
00048
00049 int m_lastPatchId = 0;
00050 for (int y = 0; y < mat.rows; y++) {
00051 for(int x = 0; x < mat.cols; x++) {
00052 if (mat.at<unsigned char>(y,x) >= threshold) {
00053
00054 int foundId = 0;
00055 int maxY = y == m_height-1?0:1;
00056 int maxX = x == m_width-1?0:1;
00057 for (int y2 = y==0?0:-1; y2 <= maxY; y2++) {
00058 for (int x2 = x==0?0:-1; x2 <= maxX; x2++) {
00059 ROS_ASSERT((y+y2)*m_width + (x+x2) < m_height*m_width);
00060 if (m_values[(y+y2)*m_width + (x+x2)] != 0) {
00061 foundId = m_values[(y+y2)*m_width + (x+x2)];
00062 break;
00063 }
00064 }
00065 if (foundId != 0)
00066 break;
00067 }
00068
00069 if (foundId != 0) {
00070 ROS_ASSERT(y*m_width + x < m_height*m_width);
00071 m_values[y*m_width + x] = foundId;
00072 } else {
00073 ROS_ASSERT(y*m_width + x < m_height*m_width);
00074 m_lastPatchId++;
00075 m_values[y*m_width + x] = m_lastPatchId;
00076 }
00077 }
00078 }
00079 }
00080
00081
00082
00083 int* eqMap = new int[m_lastPatchId+1];
00084 for (int i = 0; i < m_lastPatchId+1; i++) {
00085 ROS_ASSERT(i < m_lastPatchId+1);
00086 eqMap[i] = 0;
00087 }
00088
00089
00090
00091 for (int y = 0; y < m_height; y++) {
00092 for(int x = 0; x < m_width; x++) {
00093
00094 if (mat.at<unsigned char>(y,x) >= threshold) {
00095
00096 int mainValue = m_values[y*m_width + x];
00097 int maxY = y == m_height-1?0:1;
00098 int maxX = x == m_width-1?0:1;
00099
00100 for (int y2 = y==0?0:-1; y2 <= maxY; y2++) {
00101 for (int x2 = x==0?0:-1; x2 <= maxX; x2++) {
00102
00103 int subValue = m_values[(y+y2)*m_width + (x+x2)];
00104 if (subValue != 0 && subValue != mainValue) {
00105 M_SetEqClass(eqMap, m_lastPatchId+1, subValue, mainValue);
00106 }
00107 }
00108 }
00109 }
00110 }
00111 }
00112
00113
00114 int* finalEqMap = new int[m_lastPatchId+1];
00115 for (int i = 0; i < m_lastPatchId+1; i++) {
00116 ROS_ASSERT(i < m_lastPatchId+1);
00117 finalEqMap[i] = 0;
00118 }
00119
00120 int numEqClasses = 0;
00121 std::map<int, bool> exist;
00122
00123 for (int i = 0; i < m_lastPatchId+1; i++) {
00124 if (eqMap[i] == 0 || exist.find(eqMap[i]) == exist.end()) {
00125 numEqClasses++;
00126 if (eqMap[i] != 0) {
00127 exist[eqMap[i]] = true;
00128 for (int i2 = 0; i2 < m_lastPatchId+1; i2++) {
00129 if (eqMap[i] == eqMap[i2]) {
00130 ROS_ASSERT(i2 < m_lastPatchId+1);
00131 finalEqMap[i2] = numEqClasses;
00132 }
00133 }
00134 } else {
00135 ROS_ASSERT(i < m_lastPatchId+1);
00136 finalEqMap[i] = numEqClasses;
00137 }
00138
00139 }
00140 }
00141
00142
00143 for (int y = 0; y < m_height; y++) {
00144 for(int x = 0; x < m_width; x++) {
00145 ROS_ASSERT(y*m_width + x < m_width*m_height);
00146 if (m_values[y*m_width + x] != 0) {
00147 m_values[y*m_width + x] = finalEqMap[m_values[y*m_width + x]];
00148 }
00149 }
00150 }
00151
00152 m_count = numEqClasses;
00153
00154 delete [] finalEqMap;
00155 delete [] eqMap;
00156 }
00157
00158
00159
00161 cv::Mat ImageForest::GenerateImage() {
00162 ROS_ASSERT(m_width > 0 && m_height > 0 && m_values != 0);
00163 cv::Mat re = cv::Mat(m_height, m_width, CV_8UC3);
00164 GenerateImage(re);
00165 return re;
00166 }
00167
00168 void ImageForest::GenerateImage(cv::Mat& mat) {
00169 ROS_ASSERT(mat.channels() == 3 &&
00170 mat.cols == m_width &&
00171 mat.rows == m_height);
00172
00173 Bgr8 colors[6];
00174 colors[0].b = 255;
00175 colors[0].g = 0;
00176 colors[0].r = 0;
00177
00178 colors[1].b = 0;
00179 colors[1].g = 255;
00180 colors[1].r = 0;
00181
00182 colors[2].b = 0;
00183 colors[2].g = 0;
00184 colors[2].r = 255;
00185
00186 colors[3].b = 255;
00187 colors[3].g = 255;
00188 colors[3].r = 0;
00189
00190 colors[4].b = 0;
00191 colors[4].g = 255;
00192 colors[4].r = 255;
00193
00194 colors[5].b = 255;
00195 colors[5].g = 0;
00196 colors[5].r = 255;
00197
00198
00199 for (int y = 0; y < m_height; y++) {
00200 for (int x = 0; x < m_width; x++) {
00201 if (m_values[m_width*y + x] != 0) {
00202 ROS_ASSERT(m_values[m_width*y + x]%6 < 6 && m_values[m_width*y + x]%6 >= 0);
00203 mat.at<Bgr8>(y,x) = colors[m_values[m_width*y + x]%6];
00204 } else {
00205 mat.at<Bgr8>(y,x).b = 0;
00206 mat.at<Bgr8>(y,x).g = 0;
00207 mat.at<Bgr8>(y,x).r = 0;
00208 }
00209 }
00210 }
00211 }
00212
00213 std::map<int, ImageForest::Graph> ImageForest::GetGraphs() {
00214 if (m_count == 0) {
00215 return std::map<int,ImageForest::Graph>();
00216 }
00217
00218 std::map<int, ImageForest::Graph> graphs;
00219
00220 for (int graphId = 0; graphId < m_count; graphId++) {
00221 graphs[graphId] = ImageForest::Graph();
00222 graphs[graphId].id = graphId;
00223 graphs[graphId].numPixels = 0;
00224 }
00225
00226 for (int y = 0; y < m_height; y++) {
00227 for (int x = 0; x < m_width; x++) {
00228 int graphId = GetGraphId(x,y);
00229 if (graphId != 0) {
00230
00231 graphs[graphId].numPixels = graphs[graphId].numPixels+1;
00232
00233 int connectingNum = 0;
00234 bool found[9];
00235 for (int i = 0; i < 9; i++) {
00236 ROS_ASSERT(i < 9);
00237 found[i] = false;
00238 }
00239 int i = 0;
00240 for (int y2 = -1; y2 <= 1; y2++) {
00241 for (int x2 = -1; x2 <= 1; x2++) {
00242 if (!(y2 == 0 && x2 == 0) &&
00243 x+x2 >= 0 && x+x2 < m_width &&
00244 y+y2 >= 0 && y+y2 < m_height) {
00245
00246 int neiGraphId = GetGraphId(x+x2,y+y2);
00247 if (neiGraphId == graphId) {
00248 ROS_ASSERT(i < 9);
00249 found[i] = true;
00250 bool check = true;
00251 if (i == 1 ||
00252 i == 2 ||
00253 i == 7 ||
00254 i == 8) {
00255 ROS_ASSERT(i-1 < 9 && i-1 >= 0);
00256 check = !found[i-1];
00257 }
00258 if (i == 3 ||
00259 i == 5 ||
00260 i == 6 ||
00261 i == 8) {
00262 ROS_ASSERT(i-3 < 9 && i-3 >= 0);
00263 check = check && !found[i-3];
00264 }
00265
00266 if (check) {
00267 connectingNum++;
00268 }
00269 } else if (neiGraphId != 0) {
00270
00271 ROS_ASSERT(false);
00272 }
00273 }
00274 i++;
00275 }
00276 }
00277 if (connectingNum <= 1 ) {
00278 graphs[graphId].endPoints.push_back(Point(x,y));
00279 } else if (connectingNum > 2) {
00280 graphs[graphId].connectingPoints.push_back(Point(x,y));
00281 }
00282 }
00283 }
00284 }
00285
00286 return graphs;
00287 }
00288
00289 double ImageForest::CallculateEdgyness() {
00290 ROS_ASSERT(m_values != 0);
00291 double re = 0;
00292 for (int y = 0; y < Height(); y++) {
00293 for (int x = 0; x < Width(); x++) {
00294 if (GetGraphId(x,y) != 0) {
00295 std::vector<ImageForest::Point> vecs;
00296 M_GetVectors(x, y, vecs);
00297 std::vector<ImageForest::Point>::iterator it;
00298 double currMin = std::numeric_limits<double>::infinity();
00299 for (it = vecs.begin(); it != vecs.end(); it++) {
00300 std::vector<ImageForest::Point>::iterator it2;
00301 double currValue = 0.0;
00302 for (it2 = vecs.begin(); it2 != vecs.end(); it2++) {
00303
00304 double angle = acos(
00305 (double(it->x*it2->x + it->y*it2->y))/
00306 (sqrt(double(it->x*it->x + it->y*it->y))*sqrt(double(it2->x*it2->x + it2->y*it2->y)))
00307 );
00308
00309 if (angle > 0.1 && angle < (M_PI/4.0)+0.1) {
00310 currValue += 3.0;
00311
00312 } else if (angle > (M_PI/4.0)+0.1 && angle < (M_PI/2.0)+0.1) {
00313 currValue += 2.0;
00314
00315 } else if (angle > (M_PI/2.0)+0.1 && angle < (3.0*M_PI/4.0)+0.1) {
00316 currValue += 1.0;
00317 }
00318 }
00319 if (currValue < currMin) {
00320 currMin = currValue;
00321 }
00322 }
00323 re += currMin;
00324 }
00325 }
00326 }
00327 return re;
00328 }
00329
00330 double ImageForest::CallculateGraphMass() {
00331 double numGraphPixels = 0.0;
00332 for (int y = 0; y < Height(); y++) {
00333 for (int x = 0; x < Width(); x++) {
00334 if (GetGraphId(x,y) != 0) {
00335 numGraphPixels += 1.0;
00336 }
00337 }
00338 }
00339
00340
00341
00342 return numGraphPixels / (double(Width()*Height())-numGraphPixels);
00343 }
00344
00345 void ImageForest::M_SetEqClass(int* eqMap, int size, int a, int b) {
00346 int target = 0;
00347 std::vector<int> combine;
00348 combine.push_back(a);
00349 combine.push_back(b);
00350 if (eqMap[a] != 0) {
00351 target = eqMap[a];
00352 }
00353 if (eqMap[b] != 0 && eqMap[b] < target) {
00354 target = eqMap[b];
00355 }
00356
00357 if (eqMap[a] != 0 || eqMap[b] != 0) {
00358 for (int i = 0; i < size; i++) {
00359 if (a != i && b != i) {
00360 if (eqMap[a] != 0 && eqMap[a] == eqMap[i]) {
00361 combine.push_back(i);
00362 if (target == 0 || target > eqMap[a]) {
00363 target = eqMap[a];
00364 }
00365 } else if (eqMap[b] != 0 && eqMap[b] == eqMap[i]) {
00366 combine.push_back(i);
00367 if (target == 0 || target > eqMap[b]) {
00368 target = eqMap[b];
00369 }
00370 }
00371 }
00372 }
00373 }
00374
00375 if (target == 0) {
00376 m_lastId++,
00377 target = m_lastId;
00378 }
00379
00380 for(std::vector<int>::iterator it = combine.begin(); it < combine.end(); it++) {
00381 ROS_ASSERT(*it < size && *it >= 0);
00382 eqMap[*it] = target;
00383 }
00384 }
00385 }