$search
00001 /* 00002 * Software License Agreement (BSD License) 00003 * 00004 * Copyright (c) 2010, Willow Garage, Inc. 00005 * All rights reserved. 00006 * 00007 * Redistribution and use in source and binary forms, with or without 00008 * modification, are permitted provided that the following conditions 00009 * are met: 00010 * 00011 * * Redistributions of source code must retain the above copyright 00012 * notice, this list of conditions and the following disclaimer. 00013 * * Redistributions in binary form must reproduce the above 00014 * copyright notice, this list of conditions and the following 00015 * disclaimer in the documentation and/or other materials provided 00016 * with the distribution. 00017 * * Neither the name of Willow Garage, Inc. nor the names of its 00018 * contributors may be used to endorse or promote products derived 00019 * from this software without specific prior written permission. 00020 * 00021 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 00022 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 00023 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 00024 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 00025 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 00026 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 00027 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 00028 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 00029 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00030 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 00031 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00032 * POSSIBILITY OF SUCH DAMAGE. 00033 */ 00034 00040 #include <pcl_visualization/common/image_widget_wx.h> 00041 #include <pcl_visualization/common/float_image_utils.h> 00042 00043 #include <iostream> 00044 using std::cout; 00045 using std::cerr; 00046 00047 IMPLEMENT_APP_NO_MAIN (wxApp) 00048 00049 void 00050 pcl_visualization::ImageWidgetWX::spinOnce () 00051 { 00052 if (wxTheApp != NULL) 00053 wxTheApp->Yield (true); 00054 00055 //StopMainLoopTimer stopMainLoopTimer; 00056 //stopMainLoopTimer.Start(timeOut); 00057 //wxTheApp->OnRun(); 00058 //stopMainLoopTimer.Stop(); 00059 } 00060 00061 void 00062 pcl_visualization::ImageWidgetWX::spin () 00063 { 00064 wxTheApp->OnRun (); 00065 } 00066 00067 pcl_visualization::ImageWidgetWX::ImageWidgetWX () : keepAspectRatio (true), visualize_selected_point (false), 00068 print_selected_point(false), 00069 image_frame (NULL), image_data (NULL) 00070 { 00071 //wxInitAllImageHandlers(); 00072 if (wxTheApp == NULL) 00073 { 00074 //std::cout << "wxApp does not exist yet -> Calling wxEntryStart()\n"; 00075 int fake_argc = 0; 00076 char** fake_argv = NULL; 00077 wxEntryStart(fake_argc, fake_argv); // Initialize the wx application 00078 } 00079 else 00080 { 00081 //std::cout << "wxApp exists already.\n"; 00082 } 00083 } 00084 00085 pcl_visualization::ImageWidgetWX::~ImageWidgetWX () 00086 { 00087 //cout << __PRETTY_FUNCTION__<<" called.\n"; 00088 if (image_frame != NULL) 00089 { 00090 image_frame->parentImageWidget = NULL; 00091 image_frame->Close (true); 00092 //image_frame->Destroy(); 00093 } 00094 free (image_data); 00095 } 00096 00097 void 00098 pcl_visualization::ImageWidgetWX::reset () 00099 { 00100 mouse_click_happened = false; 00101 last_clicked_point_x = -1.0f; 00102 last_clicked_point_y = -1.0f; 00103 if (image_frame==NULL) 00104 image_frame = new ImageFrame (this); 00105 image_frame->image_panel->markedPoints.clear (); 00106 image_frame->image_panel->lines.clear (); 00107 } 00108 00109 //void pcl_visualization::ImageWidgetWX::savePng (std::string filename) const 00110 //{ 00111 //image_frame->image_panel->SaveFile(filename.c_str()); 00112 //} 00113 00114 void 00115 pcl_visualization::ImageWidgetWX::setSize (int width, int height) 00116 { 00117 int original_width = image_frame->image_panel->image->GetWidth (), 00118 original_height = image_frame->image_panel->image->GetHeight (); 00119 00120 if (width <= 0 && height <= 0) 00121 { 00122 width = original_width; 00123 height=original_height; 00124 } 00125 else if (width <= 0) 00126 { 00127 width = lrint(float(original_width) * float(height)/float(original_height)); 00128 } 00129 else if (height <= 0) 00130 { 00131 height = lrint(float(original_height) * float(width)/float(original_width)); 00132 } 00133 00134 image_frame->SetSize (wxSize (width, height)); 00135 } 00136 00137 void 00138 pcl_visualization::ImageWidgetWX::setRGBImage (const unsigned char* data, 00139 unsigned int width, unsigned int height, const char* name) 00140 { 00141 //cout << __PRETTY_FUNCTION__<<" called.\n"; 00142 reset (); 00143 00144 if (width==0 || height==0) 00145 { 00146 std::cerr << __PRETTY_FUNCTION__ << ": image has size 0.\n"; 00147 return; 00148 } 00149 00150 unsigned int arraySize = 3*width*height; 00151 if (data == NULL) arraySize=0; 00152 00153 image_data = (unsigned char*)realloc(image_data, arraySize); 00154 memcpy (image_data, data, arraySize); 00155 00156 image_frame->updateImage (image_data, width, height); 00157 image_frame->SetTitle (wxString (name, wxConvUTF8)); 00158 image_frame->image_panel->resizeImage (); 00159 image_frame->Refresh (); 00160 image_frame->Show (); 00161 } 00162 00163 void 00164 pcl_visualization::ImageWidgetWX::setName (const std::string& name) 00165 { 00166 image_frame->SetTitle (wxString (name.c_str(), wxConvUTF8)); 00167 //image_frame->Refresh (); 00168 } 00169 00170 void 00171 pcl_visualization::ImageWidgetWX::setFloatImage (const float* float_image, unsigned int width, unsigned int height, 00172 const char* name, float min_value, float max_value, bool grayscale) 00173 { 00174 unsigned char* rgb_image = FloatImageUtils::getVisualImage (float_image, width, height, 00175 min_value, max_value, grayscale); 00176 setRGBImage (rgb_image, width, height, name); 00177 delete[] rgb_image; 00178 } 00179 00180 void 00181 pcl_visualization::ImageWidgetWX::setAngleImage (const float* angle_image, unsigned int width, unsigned int height, 00182 const char* name) 00183 { 00184 unsigned char* rgb_image = FloatImageUtils::getVisualAngleImage (angle_image, width, height); 00185 setRGBImage (rgb_image, width, height, name); 00186 delete[] rgb_image; 00187 } 00188 00189 void 00190 pcl_visualization::ImageWidgetWX::setHalfAngleImage (const float* angle_image, unsigned int width, 00191 unsigned int height, const char* name) 00192 { 00193 unsigned char* rgb_image = FloatImageUtils::getVisualHalfAngleImage (angle_image, width, height); 00194 setRGBImage (rgb_image, width, height, name); 00195 delete[] rgb_image; 00196 } 00197 00198 void 00199 pcl_visualization::ImageWidgetWX::informAboutImageFrameDestruction () 00200 { 00201 //cout << __PRETTY_FUNCTION__<<" called.\n"; 00202 image_frame = NULL; 00203 } 00204 00205 void 00206 pcl_visualization::ImageWidgetWX::markPoint (float x, float y, const wxPen* color, const wxBrush* background) 00207 { 00208 image_frame->image_panel->markedPoints.push_back (ImagePoint (x,y, color, background)); 00209 } 00210 00211 void 00212 pcl_visualization::ImageWidgetWX::markLine (float x1, float y1, float x2, float y2, const wxPen* color) 00213 { 00214 image_frame->image_panel->lines.push_back (ImageLine (x1, y1, x2, y2, color)); 00215 } 00216 00217 bool 00218 pcl_visualization::ImageWidgetWX::isShown () const 00219 { 00220 if (image_frame==NULL) return false; 00221 return image_frame->IsShown (); 00222 } 00223 00224 void 00225 pcl_visualization::ImageWidgetWX::addPixelClickedHandler (PixelClickedHandler pixel_clicked_handler) 00226 { 00227 image_frame->image_panel->pixel_clicked_handlers.push_back (pixel_clicked_handler); 00228 } 00229 00230 void 00231 pcl_visualization::ImageWidgetWX::show (bool show_widget) 00232 { 00233 if (image_frame != NULL) 00234 image_frame->Show (show_widget); 00235 } 00236 00237 00238 //================================== 00239 // IMAGE FRAME DEFINITION START 00240 //================================== 00241 00242 00243 pcl_visualization::ImageWidgetWX::ImageFrame::ImageFrame (ImageWidgetWX* parentImageWidget) : 00244 wxFrame (NULL, wxID_ANY, wxString (__func__, wxConvUTF8), wxPoint (50, 50), wxSize (800, 600)), 00245 parentImageWidget (parentImageWidget) 00246 { 00247 image_panel = new ImagePanel (this); 00248 //wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL); 00249 //sizer->Add(image_panel, 1, wxEXPAND); 00250 //this->SetSizer(sizer); 00251 } 00252 00253 pcl_visualization::ImageWidgetWX::ImageFrame::~ImageFrame() 00254 { 00255 //cout << __PRETTY_FUNCTION__<<" called.\n"; 00256 if (parentImageWidget != NULL) 00257 parentImageWidget->informAboutImageFrameDestruction (); 00258 //delete image_panel; // This is done by wxApp 00259 } 00260 00261 BEGIN_EVENT_TABLE (pcl_visualization::ImageWidgetWX::ImageFrame, wxFrame) 00262 //EVT_PAINT(ImageWidgetWX::ImageFrame::paintEvent) 00263 EVT_SIZE (pcl_visualization::ImageWidgetWX::ImageFrame::OnSize) 00264 EVT_CLOSE (pcl_visualization::ImageWidgetWX::ImageFrame::OnClose) // Subscribe for the close event 00265 END_EVENT_TABLE () 00266 00267 void 00268 pcl_visualization::ImageWidgetWX::ImageFrame::OnSize(wxSizeEvent& event) 00269 { 00270 //cout << __PRETTY_FUNCTION__<<" called.\n"; 00271 Fit (); 00272 event.Skip (); 00273 } 00274 00275 void 00276 pcl_visualization::ImageWidgetWX::ImageFrame::OnClose (wxCloseEvent& event) 00277 { 00278 //cout << __PRETTY_FUNCTION__<<" called.\n"; 00279 //this->Destroy(); // If not, destroy the window anyway. 00280 event.Skip (); 00281 } 00282 00283 void 00284 pcl_visualization::ImageWidgetWX::ImageFrame::updateImage (unsigned char* data, 00285 unsigned int width, unsigned int height) 00286 { 00287 //cout << __PRETTY_FUNCTION__<<" called.\n"; 00288 //delete image_panel->image; image_panel->image=NULL; 00289 00290 delete image_panel->image; 00291 image_panel->image = NULL; 00292 00293 if (data == NULL) return; 00294 00295 bool letWxDeleteIt = false; 00296 image_panel->image = new wxImage (width, height, data, !letWxDeleteIt); 00297 } 00298 00299 00300 //================================== 00301 // IMAGE PANEL DEFINITION START 00302 //================================== 00303 00304 BEGIN_EVENT_TABLE (pcl_visualization::ImageWidgetWX::ImagePanel, wxPanel) 00305 /* some useful events 00306 EVT_MOTION(ImageWidgetWX::ImagePanel::mouseMoved) 00307 EVT_LEFT_DOWN(ImageWidgetWX::ImagePanel::mouseDown) 00308 EVT_RIGHT_DOWN(ImageWidgetWX::ImagePanel::rightClick) 00309 EVT_LEAVE_WINDOW(ImageWidgetWX::ImagePanel::mouseLeftWindow) 00310 EVT_KEY_DOWN(ImageWidgetWX::ImagePanel::keyPressed) 00311 EVT_KEY_UP(ImageWidgetWX::ImagePanel::keyReleased) 00312 EVT_MOUSEWHEEL(ImageWidgetWX::ImagePanel::mouseWheelMoved) 00313 */ 00314 EVT_LEFT_UP (pcl_visualization::ImageWidgetWX::ImagePanel::mouseReleased) 00315 EVT_PAINT (pcl_visualization::ImageWidgetWX::ImagePanel::paintEvent) // catch paint events 00316 EVT_SIZE (pcl_visualization::ImageWidgetWX::ImagePanel::OnSize) // Size event 00317 END_EVENT_TABLE () 00318 /* some useful events 00319 void ImageWidgetWX::ImagePanel::mouseMoved(wxMouseEvent& event) {} 00320 void ImageWidgetWX::ImagePanel::mouseDown(wxMouseEvent& event) {} 00321 void ImageWidgetWX::ImagePanel::mouseWheelMoved(wxMouseEvent& event) {} 00322 void ImageWidgetWX::ImagePanel::rightClick(wxMouseEvent& event) {} 00323 void ImageWidgetWX::ImagePanel::mouseLeftWindow(wxMouseEvent& event) {} 00324 void ImageWidgetWX::ImagePanel::keyPressed(wxKeyEvent& event) {} 00325 void ImageWidgetWX::ImagePanel::keyReleased(wxKeyEvent& event) {} 00326 */ 00327 00328 pcl_visualization::ImageWidgetWX::ImagePanel::ImagePanel (wxFrame* parent) : wxPanel (parent), image (NULL), 00329 scaledWidth (0), scaledHeight (0) 00330 { 00331 } 00332 00333 pcl_visualization::ImageWidgetWX::ImagePanel::~ImagePanel () 00334 { 00335 //cout << __PRETTY_FUNCTION__<<" called.\n"; 00336 } 00337 00338 /* 00339 * Called by the system by wxWidgets when the panel needs 00340 * to be redrawn. You can also trigger this call by 00341 * calling Refresh()/Update(). 00342 */ 00343 void 00344 pcl_visualization::ImageWidgetWX::ImagePanel::paintEvent (wxPaintEvent & evt) 00345 { 00346 //cout << __PRETTY_FUNCTION__<<" called.\n"; 00347 // depending on your system you may need to look at double-buffered dcs 00348 wxPaintDC dc (this); 00349 render (dc); 00350 } 00351 00352 void 00353 pcl_visualization::ImageWidgetWX::ImagePanel::mouseReleased (wxMouseEvent& event) 00354 { 00355 //std::cout << __PRETTY_FUNCTION__<<" called.\n"; 00356 float clicked_pixel_x = (float)event.m_x * (float)image->GetWidth ()/(float)scaledWidth -0.5f, 00357 clicked_pixel_y = (float)event.m_y * (float)image->GetHeight ()/(float)scaledHeight -0.5f; 00358 getParentImageWidget()->mouse_click_happened = true; 00359 getParentImageWidget()->last_clicked_point_x = clicked_pixel_x; 00360 getParentImageWidget()->last_clicked_point_y = clicked_pixel_y; 00361 //std::cout << "New pixel was clicked: "<<clicked_pixel_x<<"," 00362 //<<clicked_pixel_y<<".\n"; 00363 00364 if (getParentImageWidget()->print_selected_point) 00365 cout << "ImageWidgetWX: Clicked image point is " << clicked_pixel_x<<", "<<clicked_pixel_y<<".\n"; 00366 // Call handler functions 00367 for (unsigned int i = 0; i < pixel_clicked_handlers.size(); ++i) 00368 pixel_clicked_handlers[i] (clicked_pixel_x, clicked_pixel_y); 00369 Refresh (); 00370 } 00371 00372 00373 /* 00374 * Alternatively, you can use a clientDC to paint on the panel 00375 * at any time. Using this generally does not free you from 00376 * catching paint events, since it is possible that e.g. the window 00377 * manager throws away your drawing when the window comes to the 00378 * background, and expects you will redraw it when the window comes 00379 * back (by sending a paint event). 00380 */ 00381 void 00382 pcl_visualization::ImageWidgetWX::ImagePanel::paintNow () 00383 { 00384 // depending on your system you may need to look at double-buffered dcs 00385 wxClientDC dc (this); 00386 render (dc); 00387 } 00388 00389 /* 00390 * Here we do the actual rendering. I put it in a separate 00391 * method so that it can work no matter what type of DC 00392 * (e.g. wxPaintDC or wxClientDC) is used. 00393 */ 00394 void 00395 pcl_visualization::ImageWidgetWX::ImagePanel::render (wxDC& dc) 00396 { 00397 //cout << __PRETTY_FUNCTION__<<" called.\n"; 00398 if (image==NULL) return; 00399 00400 int newWidth, newHeight; 00401 dc.GetSize (&newWidth, &newHeight); 00402 00403 if (newWidth != scaledWidth || newHeight != scaledHeight) 00404 { 00405 resizeImage (newWidth, newHeight); 00406 } 00407 dc.DrawBitmap (resized_, 0, 0, false); 00408 00409 int circleSize = 4; 00410 for (unsigned int i = 0; i < markedPoints.size (); ++i) 00411 { 00412 const ImagePoint& point = markedPoints.at (i); 00413 dc.SetPen (*point.color); 00414 dc.SetBrush (*point.background); 00415 dc.DrawEllipse (lrint ((point.x+0.5f)*scaledWidth / image->GetWidth ())-0.5f*circleSize, 00416 lrint ((point.y+0.5f)*scaledHeight / image->GetHeight ())-0.5f*circleSize, circleSize, circleSize); 00417 } 00418 00419 for (unsigned int i = 0; i < lines.size (); ++i) 00420 { 00421 const ImageLine& line = lines.at (i); 00422 wxPoint points_array[2]; 00423 points_array[0].x = lrint ((line.x1+0.5f)*scaledWidth / image->GetWidth ()); 00424 points_array[0].y = lrint ((line.y1+0.5f)*scaledHeight / image->GetHeight ()); 00425 points_array[1].x = lrint((line.x2+0.5f)*scaledWidth / image->GetWidth ()); 00426 points_array[1].y = lrint((line.y2+0.5f)*scaledHeight / image->GetHeight ()); 00427 wxPen pen(*line.color); 00428 pen.SetWidth(3); 00429 dc.SetPen(pen); 00430 dc.DrawLines (2, points_array); 00431 } 00432 00433 if (getParentImageWidget()->visualize_selected_point) 00434 { 00435 int selected_x = getParentImageWidget()->last_clicked_point_x, 00436 selected_y = getParentImageWidget()->last_clicked_point_y; 00437 if (selected_x >= 0 && selected_y >= 0) 00438 { 00439 wxPen pen(*wxGREEN, 2); 00440 dc.SetPen (pen); 00441 dc.CrossHair (lrint((selected_x+0.5f)*scaledWidth / image->GetWidth ()), 00442 lrint((selected_y+0.5f)*scaledHeight / image->GetHeight ())); 00443 } 00444 } 00445 } 00446 00447 /* 00448 * Here we call refresh to tell the panel to draw itself again. 00449 * So when the user resizes the image panel the image should be resized too. 00450 */ 00451 void 00452 pcl_visualization::ImageWidgetWX::ImagePanel::OnSize (wxSizeEvent& event) 00453 { 00454 event.Skip (); 00455 if (getParentImageWidget ()->keepAspectRatio) 00456 { 00457 float aspectRatio = (float)image->GetWidth () / (float)image->GetHeight (); 00458 SetSize (wxDefaultCoord, wxDefaultCoord, event.GetSize ().GetWidth (), 00459 lrint((float)event.GetSize ().GetWidth () / aspectRatio)); 00460 } 00461 Refresh (); 00462 } 00463 00464 void 00465 pcl_visualization::ImageWidgetWX::ImagePanel::resizeImage (int newWidth, int newHeight) 00466 { 00467 if (newWidth<=0 || newHeight<=0) // No size given => Use current widget size 00468 this->GetSize (&newWidth, &newHeight); 00469 00470 resized_ = wxBitmap (image->Scale (newWidth, newHeight)); 00471 //resized_ = wxBitmap(image->Scale (newWidth, newHeight, wxIMAGE_QUALITY_HIGH)); 00472 scaledWidth = newWidth; 00473 scaledHeight = newHeight; 00474 //cout << "Image has new size "<<scaledWidth<<"x"<<scaledHeight<<"\n"; 00475 } 00476