segmentation
All Data Structures Namespaces Files Functions Variables Modules Pages
lumaChroma.cpp
1 /*
2  * Copyright (C) 2011 Department of Robotics Brain and Cognitive Sciences - Istituto Italiano di Tecnologia
3  * Authors: Vadim Tikhanoff, Andrew Dankers
4  * email: vadim.tikhanoff@iit.it
5  * website: www.robotcub.org
6  * Permission is granted to copy, distribute, and/or modify this program
7  * under the terms of the GNU General Public License, version 2 or any
8  * later version published by the Free Software Foundation.
9  *
10  * A copy of the license can be found at
11  * http://www.robotcub.org/icub/license/gpl.txtd
12  *
13  * This program is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
16  * Public License for more details
17  */
18 
19 #include <yarp/cv/Cv.h>
20 #include "lumaChroma.h"
21 #include <cstdio>
22 #include <cstdlib>
23 #include <cstring>
24 
25 const int KERNSIZEMAX = 9;
26 
27 using namespace std;
28 using namespace yarp::os;
29 using namespace yarp::sig;
30 using namespace yarp::cv;
31 
32 bool lumaChroma::configure(yarp::os::ResourceFinder &rf)
33 {
34  /* Process all parameters from both command-line and .ini file */
35 
36  moduleName = rf.check("name",
37  Value("lumaChroma"),
38  "module name (string)").asString();
39 
40  setName(moduleName.c_str());
41 
42  imageType = rf.check("image",
43  Value("yuv"),
44  "image type (string)").asString();
45 
46  whichPort = rf.check("out",
47  Value(""),
48  "default port (string)").asString();
49 
50  /*
51  * attach a port of the same name as the module (prefixed with a /) to the module
52  * so that messages received from the port are redirected to the respond method
53  */
54 
55  handlerPortName = "/";
56  handlerPortName += getName(); // use getName() rather than a literal
57 
58  if (!handlerPort.open(handlerPortName.c_str()))
59  {
60  cout << getName() << ": Unable to open port " << handlerPortName << endl;
61  return false;
62  }
63 
64  attach(handlerPort); // attach to port
65 
66  /* create the thread and pass pointers to the module parameters */
67  procThread = new PROCThread(moduleName, imageType, whichPort);
68 
69  /* now start the thread to do the work */
70  procThread->open();
71 
72  return true ; // let the RFModule know everything went well
73 }
74 
75 bool lumaChroma::interruptModule()
76 {
77  handlerPort.interrupt();
78  return true;
79 }
80 
81 bool lumaChroma::close()
82 {
83  handlerPort.close();
84  /* stop the thread */
85  cout << "starting the shutdown procedure " << endl;
86  procThread->interrupt();
87  procThread->close();
88  fprintf(stdout, "deleting thread \n");
89  delete procThread;
90  fprintf(stdout, "done deleting thread \n");
91  return true;
92 }
93 
94 bool lumaChroma::respond(const Bottle& command, Bottle& reply)
95 {
96  reply.clear();
97 
98  if (command.get(0).asString()=="quit")
99  {
100  reply.addString("quitting");
101  return false;
102  }
103  else if (command.get(0).asString()=="help")
104  {
105  cout << "Options:" << endl << endl;
106  cout << "\t--name name: module name (default: lumaChroma)" << endl;
107  cout << "\t--image type: image type to process (default: yuv)" << endl;
108  cout << "\t--out default port: duplicates the out port with a default name" << endl;
109  reply.addString("ok");
110  }
111  else
112  {
113  cout << "command not known - type help for more info" << endl;
114  }
115  return true;
116 }
117 
118 /* Called periodically every getPeriod() seconds */
119 
120 bool lumaChroma::updateModule()
121 {
122  return true;
123 }
124 
125 double lumaChroma::getPeriod()
126 {
127  return 0.1;
128 }
129 
130 PROCThread::~PROCThread()
131 {
132 
133 }
134 
135 PROCThread::PROCThread( const string &moduleName, const string &imgType, const string &whichPort )
136 {
137  isYUV = true;
138 
139  //set up default port name
140  this->whichPort = whichPort;
141 
142  //set up module name
143  this->moduleName = moduleName;
144 
145  //set up module name
146  if (imgType == "yuv" || imgType == "YUV")
147  {
148  cout << "will run module using the YUV image colour space" << endl;
149  if (whichPort.size() == 0)
150  this->whichPort = "Y";
151  }
152  else if (imgType == "hsv" || imgType == "HSV")
153  {
154  isYUV = false;
155  cout << "will run module using the HSV image colour space" << endl;
156  if (whichPort.size() == 0)
157  this->whichPort = "S";
158  }
159  else
160  {
161  cout << "probably an error in the colour space will use default: YUV" << endl;
162  }
163  cout << "initialising Variables" << endl;
164 
165  img_out_Y = NULL;
166  img_out_UV = NULL;
167  img_out_V = NULL;
168  inputExtImage = NULL;
169  img_Y = NULL;
170  img_UV = NULL;
171  img_V = NULL;
172  centerSurr = NULL;
173  allocated = false;
174 }
175 
176 bool PROCThread::open()
177 {
178  string temp[3];
179  if ( isYUV ){
180  temp[0] = "Y";
181  temp[1] = "UV";
182  }else{
183  temp[0] = "H";
184  temp[1] = "S";
185  temp[2] = "V";
186  }
187 
188  this->useCallback();
189 
190  //create all ports
191  inputPortName = "/" + moduleName + "/image:i";
192  BufferedPort<ImageOf<PixelRgb> >::open( inputPortName.c_str() );
193 
194  outputPortName = "/" + moduleName + "/propImg:o";
195  imageOutPort.open( outputPortName.c_str() );
196 
197  outputPortName1 = "/" + moduleName + "/" + temp[0] + "/image:o";
198  imageOutPort1.open( outputPortName1.c_str() );
199 
200  outputPortName2 = "/" + moduleName + "/" + temp[1] + "/image:o";
201  imageOutPort2.open( outputPortName2.c_str() );
202 
203  if (!isYUV)
204  {
205  outputPortName3 = "/" + moduleName + "/" + temp[2] + "/image:o";
206  imageOutPort3.open( outputPortName3.c_str() );
207  }
208 
209  outputPortNameDefault = "/" + moduleName + "/image:o";
210  defaultPortOut.open( outputPortNameDefault.c_str() );
211 
212  check=false;
213 
214  return true;
215 }
216 
217 void PROCThread::onRead(ImageOf<yarp::sig::PixelRgb> &img)
218 {
219  lock_guard<mutex> lg(mtx);
220  if(check)
221  {
222  return;
223  }
224 
225  if( !allocated || img.width() != img_out_Y->width() || img.height() != img_out_Y->height() )
226  {
227  deallocate();
228  allocate( img );
229  }
230  extender( img, KERNSIZEMAX );
231  cv::Mat inputMat=toCvMat(*inputExtImage);
232  if ( isYUV )
233  cv::cvtColor( inputMat, orig, CV_RGB2YCrCb);
234  else
235  cv::cvtColor( inputMat, orig, CV_RGB2HSV);
236 
237  vector<cv::Mat> planes;
238  cv::split(orig, planes);
239  //performs centre-surround uniqueness analysis on first plane
240  centerSurr->proc_im_8u( planes[0] );
241 
242  cv::Mat y_img = centerSurr->get_centsur_norm8u();
243  y_img.copyTo(toCvMat(*img_Y));
244  csTot32f.setTo(cv::Scalar(0));
245 
246  //performs centre-surround uniqueness analysis on second plane:
247  centerSurr->proc_im_8u( planes[1] );
248  if ( isYUV )
249  cv::add(centerSurr->get_centsur_32f(), csTot32f, csTot32f);
250  else
251  {
252  cv::Mat s_img = centerSurr->get_centsur_norm8u();
253  s_img.copyTo(toCvMat(*img_UV));
254  }
255  //performs centre-surround uniqueness analysis on third plane:
256  centerSurr->proc_im_8u( planes[2] );
257  if ( isYUV )
258  cv::add(centerSurr->get_centsur_32f(), csTot32f, csTot32f);
259  else
260  {
261  cv::Mat v_img = centerSurr->get_centsur_norm8u();
262  v_img.copyTo(toCvMat(*img_V));
263  }
264  if ( isYUV )
265  {
266  //get min max
267  double valueMin = 0.0f;
268  double valueMax = 0.0f;
269  cv::minMaxLoc(csTot32f, &valueMin, &valueMax);
270  if ( valueMax == valueMin )
271  {
272  valueMax = 255.0f; valueMin = 0.0f;
273  }
274  cv::convertScaleAbs( csTot32f, uvimg, 255/(valueMax - valueMin), -255*valueMin/(valueMax-valueMin) );
275  uvimg.copyTo(toCvMat(*img_UV));
276  }
277  //this is nasty, resizes the images...
278  unsigned char* imgY = img_Y->getPixelAddress( KERNSIZEMAX, KERNSIZEMAX );
279  unsigned char* imgUV = img_UV->getPixelAddress( KERNSIZEMAX, KERNSIZEMAX );
280  unsigned char* imgV;
281  unsigned char* imgVo;
282 
283  if (!isYUV)
284  {
285  imgV = img_V->getPixelAddress( KERNSIZEMAX, KERNSIZEMAX );
286  imgVo = img_out_V->getRawImage();
287  }
288  unsigned char* imgYo = img_out_Y->getRawImage();
289  unsigned char* imgUVo = img_out_UV->getRawImage();
290  int rowsize= img_out_Y->getRowSize();
291  int rowsize2= img_Y->getRowSize();
292  for(int row=0; row<origsize.height; row++)
293  {
294  for(int col=0; col<origsize.width; col++)
295  {
296  *imgYo = *imgY;
297  *imgUVo = *imgUV;
298  if (!isYUV)
299  {
300  *imgVo = *imgV;
301  imgVo++; imgV++;
302  }
303  imgYo++; imgUVo++;
304  imgY++; imgUV++;
305  }
306  imgYo+=rowsize - origsize.width;
307  imgUVo+=rowsize - origsize.width;
308  imgY+=rowsize2 - origsize.width;
309  imgUV+=rowsize2 - origsize.width;
310  if (!isYUV)
311  {
312  imgVo+=rowsize - origsize.width;
313  imgV+=rowsize2 - origsize.width;
314  }
315  }
316 
317  //output Y or H centre-surround results to ports
318  if ( imageOutPort1.getOutputCount()>0 )
319  {
320  imageOutPort1.prepare() = *img_out_Y;
321  imageOutPort1.write();
322  }
323 
324  //output UV or V centre-surround results to ports
325  if ( imageOutPort2.getOutputCount()>0 )
326  {
327  imageOutPort2.prepare() = *img_out_UV;
328  imageOutPort2.write();
329  }
330  //output H centre-surround results to ports
331  if ( !isYUV && imageOutPort3.getOutputCount()>0 )
332  {
333  imageOutPort3.prepare() = *img_out_V;
334  imageOutPort3.write();
335  }
336 
337  if ( defaultPortOut.getOutputCount()>0 )
338  {
339  if (!isYUV && whichPort=="v" || !isYUV && whichPort == "V" )
340  defaultPortOut.prepare() = *img_out_V;
341  else if (whichPort=="y" || whichPort == "Y" || whichPort=="h" || whichPort == "H")
342  defaultPortOut.prepare() = *img_out_Y;
343  else if (whichPort=="u" || whichPort == "U" || whichPort=="v" || whichPort == "V" || whichPort=="uv" || whichPort == "UV" || whichPort=="s" || whichPort == "S" )
344  defaultPortOut.prepare() = *img_out_UV;
345  else
346  fprintf(stdout, "something went wrong\n");
347 
348  imageOutPort.prepare() = img;
349  defaultPortOut.write();
350  imageOutPort.write();
351  }
352 }
353 
354 void PROCThread::allocate( ImageOf<PixelRgb> &img )
355 {
356  origsize.width = img.width();
357  origsize.height = img.height();
358 
359  srcsize.width = origsize.width + 2 * KERNSIZEMAX;
360  srcsize.height = origsize.height + KERNSIZEMAX;
361 
362  cout << "Received input image dimensions: " << origsize.width << " " << origsize.height << endl;
363  cout << "Will extend these to: " << srcsize.width << " " << srcsize.height << endl;
364 
365  orig = cv::Mat(srcsize.width, srcsize.height, CV_8UC3);
366  csTot32f = cv::Mat( srcsize.height, srcsize.width, CV_32FC1 );
367  uvimg = cv::Mat( srcsize.height, srcsize.width, CV_32FC1 );
368 
369  ncsscale = 4;
370  centerSurr = new CentSur( srcsize , ncsscale );
371 
372  inputExtImage = new ImageOf<PixelRgb>;
373  inputExtImage->resize( srcsize.width, srcsize.height );
374 
375  img_Y = new ImageOf<PixelMono>;
376  img_Y->resize( srcsize.width, srcsize.height );
377 
378  img_out_Y = new ImageOf<PixelMono>;
379  img_out_Y->resize( origsize.width, origsize.height );
380 
381  img_UV = new ImageOf<PixelMono>;
382  img_UV->resize( srcsize.width, srcsize.height );
383 
384  img_out_UV = new ImageOf<PixelMono>;
385  img_out_UV->resize( origsize.width, origsize.height );
386 
387  img_V = new ImageOf<PixelMono>;
388  img_V->resize( srcsize.width, srcsize.height );
389 
390  img_out_V = new ImageOf<PixelMono>;
391  img_out_V->resize( origsize.width, origsize.height );
392 
393  allocated = true;
394  cout << "done allocating" << endl;
395 }
396 
397 void PROCThread::deallocate( )
398 {
399  delete img_out_Y;
400  delete img_out_UV;
401  delete img_out_V;
402  delete img_Y;
403  delete img_UV;
404  delete img_V;
405  delete inputExtImage;
406  img_out_Y = NULL;
407  img_out_UV = NULL;
408  img_out_V = NULL;
409  inputExtImage = NULL;
410  img_Y = NULL;
411  img_UV = NULL;
412  img_V = NULL;
413  delete centerSurr;
414  centerSurr = NULL;
415 
416  orig.release();
417  uvimg.release();
418  csTot32f.release();
419 
420  allocated = false;
421 }
422 
423 void PROCThread::close()
424 {
425  cout << "now closing ports..." << endl;
426  lock_guard<mutex> lg(mtx);
427  imageOutPort.close();
428  imageOutPort1.close();
429  imageOutPort2.close();
430  if ( !isYUV )
431  imageOutPort3.close();
432  defaultPortOut.close();
433 
434  deallocate();
435  cout << "deallocated all attempting to close read port..." << endl;
436  BufferedPort<ImageOf<PixelRgb> >::close();
437  cout << "finished closing the read port..." << endl;
438 }
439 
440 void PROCThread::interrupt()
441 {
442  lock_guard<mutex> lg(mtx);
443  check=true;
444  cout << "cleaning up..." << endl;
445  cout << "attempting to interrupt ports" << endl;
446 
447  imageOutPort.interrupt();
448  imageOutPort1.interrupt();
449  imageOutPort2.interrupt();
450 
451  if ( !isYUV )
452  imageOutPort3.interrupt();
453 
454  defaultPortOut.interrupt();
455 
456  BufferedPort<ImageOf<PixelRgb> >::interrupt();
457  cout << "finished interrupt ports" << endl;
458 }
459 
460 ImageOf<PixelRgb>* PROCThread::extender(ImageOf<PixelRgb>& inputOrigImage, int maxSize)
461 {
462  // copy of the image
463  inputExtImage->copy( inputOrigImage, srcsize.width, srcsize.height );
464  // memcpy of the horizontal fovea lines (rows)
465  const int sizeBlock = origsize.width / 2;
466  for(int i = 0; i < maxSize; i++)
467  {
468  memcpy( inputExtImage->getPixelAddress( sizeBlock + maxSize, maxSize-1-i ),
469  inputExtImage->getPixelAddress( maxSize, maxSize+i ),
470  sizeBlock*sizeof(PixelRgb));
471  memcpy( inputExtImage->getPixelAddress( maxSize, maxSize-1-i ),
472  inputExtImage->getPixelAddress( sizeBlock + maxSize, maxSize+i ),
473  sizeBlock*sizeof(PixelRgb));
474  }
475  // copy of the block adjacent angular positions (columns)
476  const int px = maxSize * sizeof(PixelRgb);
477 
478  for (int row = 0; row < srcsize.height; row++)
479  {
480  memcpy ( inputExtImage->getPixelAddress( srcsize.width-maxSize, row ),
481  inputExtImage->getPixelAddress( maxSize,row ), px);
482  memcpy ( inputExtImage->getPixelAddress( 0, row ),
483  inputExtImage->getPixelAddress( srcsize.width- maxSize-maxSize, row ), px);
484  }
485  return inputExtImage;
486 }
487 
488