<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;CUcBRnozcSp7ImA9WhRVEUQ.&quot;"><id>tag:blogger.com,1999:blog-19722740</id><updated>2012-01-10T11:57:37.489+01:00</updated><category term="mobile" /><category term="systemy interaktywne" /><category term="linux" /><category term="xml" /><category term="creative common" /><category term="dicom" /><category term="Insight Toolkit (ITK)" /><category term="meego" /><category term="segmentacja" /><category term="rozwiązania" /><category term="OpenCV" /><category term="wizualizacja" /><category term="Tcl" /><category term="tomografia" /><category term="KWWidgets" /><category term="kde" /><category term="oracle" /><category term="pandore" /><category term="licencje" /><category term="pomiary" /><category term="Visualization ToolKit (VTK)" /><category term="cmake" /><category term="ImageMagick" /><category term="analiza obrazu" /><category term="video" /><category term="Qt" /><category term="docbook" /><category term="otwarty kod" /><category term="książki" /><category term="aplikacje" /><category term="cimg" /><category term="rekomendowane technologie" /><category term="google" /><category term="galeria" /><title>Rafał Petryniak</title><subtitle type="html">Blog techniczny o przetwarzaniu obrazów i nie tylko</subtitle><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://rpetryniak.blogspot.com/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://rpetryniak.blogspot.com/" /><link rel="next" type="application/atom+xml" href="http://www.blogger.com/feeds/19722740/posts/default?start-index=26&amp;max-results=25&amp;redirect=false&amp;v=2" /><author><name>Rafał Petryniak</name><uri>https://profiles.google.com/106420849521837640393</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-ueopwOVHATs/AAAAAAAAAAI/AAAAAAAAGaw/TSrE-0eH8Zc/s512-c/photo.jpg" /></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>76</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/RafalPetryniakBlog" /><feedburner:info uri="rafalpetryniakblog" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry gd:etag="W/&quot;CUcBRnoyfSp7ImA9WhRVEUQ.&quot;"><id>tag:blogger.com,1999:blog-19722740.post-6929275232637461868</id><published>2012-01-09T22:54:00.001+01:00</published><updated>2012-01-10T11:57:37.495+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-10T11:57:37.495+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="otwarty kod" /><category scheme="http://www.blogger.com/atom/ns#" term="systemy interaktywne" /><category scheme="http://www.blogger.com/atom/ns#" term="OpenCV" /><title>Aplikacja interaktywna w OpenCV reagującą na ruch</title><content type="html">&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;
&lt;div style="text-align: right;"&gt;
&lt;/div&gt;
&lt;table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; margin-left: 1em; text-align: right;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;span style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;"&gt;&lt;a href="http://www.blogger.com/goog_627283070"&gt;&lt;img border="0" src="http://riad.pk.edu.pl/~rpetryniak/website_resources/images/logo/github-logo1.png" /&gt;&lt;/a&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;&lt;a href="https://github.com/rpetryniak/OpenCv-Interactive-Apps-And-Examples/tree/master/InteractiveAppTutorial/InteractiveAppTutorial_5" target="_blank"&gt;Pełny kod źródłowy&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
Kurs programowania systemów interaktywnych z wykorzystaniem &lt;b&gt;&lt;i&gt;OpenCV&lt;/i&gt;&lt;/b&gt;, który jakiś czas temu rozpocząłem na łamach tego bloga (patrz: &lt;a href="http://rpetryniak.blogspot.com/search/label/OpenCV" target="_blank"&gt;etykieta OpenCV&lt;/a&gt;), byłby niekompletny, gdyby zabrakło opisu interakcji ruchowej. &lt;a href="http://rpetryniak.blogspot.com/2011/05/opencv-obsuga-klawiatury-i-myszki.html" target="_blank"&gt;Obsługa klawiatury i myszki&lt;/a&gt;&amp;nbsp;są oczywiście ważne, ale już na nikim nie robią szczególnego wrażenia. &lt;i&gt;OpenCV&lt;/i&gt; jak wiadomo jest przeznaczony do śledzenia i analizy ruchu i to jest jego główna siła.&lt;br /&gt;
&lt;br /&gt;
W dzisiejszym wpisie zostanie pokazane jak dodać kolejną warstwę interakcji poprzez analizę i detekcję ruchu. Wpis ten będzie naturalnym rozszerzeniem przykładów omawianych wcześniej, dlatego zachęcam do ich wcześniejszej analizy. Szczególnie istotne są dwa z nich:&lt;br /&gt;
&lt;ul style="text-align: left;"&gt;
&lt;li&gt;&lt;a href="http://rpetryniak.blogspot.com/2011/05/opencv-obsuga-klawiatury-i-myszki.html" target="_blank"&gt;OpenCV - obsługa klawiatury i myszki&lt;/a&gt; [&lt;i&gt;16 maj 2011&lt;/i&gt;]&lt;/li&gt;
&lt;li&gt;&lt;a href="http://rpetryniak.blogspot.com/2011/04/detekcja-ruchu-w-opencv-porownanie.html" target="_blank"&gt;Detekcja ruchu w OpenCV - porównanie klatek&lt;/a&gt; [&lt;i&gt;6 kwi 2011&lt;/i&gt;]&lt;/li&gt;
&lt;/ul&gt;
Dobra wiadomość jest taka, że dzięki wprowadzeniu &lt;a href="http://rpetryniak.blogspot.com/2011/04/poprawiony-szkielet-aplikacji.html" target="_blank"&gt;obiektowego szkieletu aplikacji&lt;/a&gt;, rozszerzenie aplikacji o interakcję ruchową będzie niezwykle proste i nie będzie wymagało wielu zmian w kodzie. Dla przykładu kod &lt;i&gt;kulki&lt;/i&gt; praktycznie pozostaje bez zmian. Logika aplikacji jest również taka sama jak dla &lt;a href="http://rpetryniak.blogspot.com/2011/05/opencv-obsuga-klawiatury-i-myszki.html" target="_blank"&gt;poprzedniego przykładu&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Pierwszą rzeczą, którą należy zrobić jest dodanie kilku pomocniczych zmiennych, które będą zawierać pośrednie etapu przetwarzania obrazu.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint lang-cpp notranslate"&gt;// plik: &lt;b&gt;interactive_app_tutorial-MainApp.h&lt;/b&gt;
class MainApp
{
private:
  Mat cam_frame, img_gray, img_first, img_prev, img_diff, img_bin;&lt;/pre&gt;
&lt;br /&gt;
Następnie należy rozszerzyć funkcję &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;u&gt;update&lt;/u&gt;&lt;/span&gt; klasy &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;u&gt;MainApp&lt;/u&gt;&lt;/span&gt;&amp;nbsp;o sprawdzanie na ile każda z kulek pokrywa się z fragmentami obrazu binarnego, gdzie został wykryty ruch.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint lang-cpp notranslate"&gt;// plik: &lt;b&gt;interactive_app_tutorial-MainApp.cpp&lt;/b&gt;
for (int k = 0; k &amp;lt; myBall.size(); k++) {
  movementAmount = 0;
  ball_dim = myBall[k].getDim();
  ball_x   = myBall[k].getX();
  ball_y   = myBall[k].getY();
  
  for (int i=(-1*ball_dim); i&amp;lt;ball_dim; i++)
    for (int j=(-1*ball_dim); j&amp;lt;ball_dim; j++)
      if ( dist(0,0,i,j) &amp;lt; ball_dim ) {          
        canvas_ind_x = ball_x + i;
        canvas_ind_y = ball_y + j;
        
        if ( canvas_ind_x&amp;lt;=0 || canvas_ind_y&amp;lt;=0 || 
             canvas_ind_x&amp;gt;CANVAS_WIDTH || canvas_ind_y&amp;gt;CANVAS_HEIGHT) 
          continue; 
        
        if ( img_bin.at&amp;lt;uchar&amp;gt;(canvas_ind_y,canvas_ind_x) &amp;gt; 30) {
          movementAmount++;
        }
      }
      
      if (movementAmount &amp;gt; max_motion_points)
        myBall[k].decrementLives();
      else
        if (!pauseBallsMove) myBall[k].update();
}&lt;/pre&gt;
&lt;br /&gt;
W powyższym przykładzie widać, że jeśli więcej niż 30 pikseli leży na masce (zmienna &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;img_bin&lt;/span&gt;) wskazującej miejsce detekcji ruchu to możemy uznać, że kulka została "dotknięta". Oczywiście można zmienić tą wartość na inną, lub nawet ustalać ją w zależności od wielkości elementu zbijanego. To prawdopodobnie byłoby lepsze rozwiązanie od obecnego, ale jak widać na poniższym filmie, obecne również daje radę :-)&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: center;"&gt;
&lt;iframe allowfullscreen="" frameborder="0" height="284" src="http://www.youtube.com/embed/Li_iCYl2ZQs" width="500"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;div style="text-align: center;"&gt;
&lt;i&gt;&lt;a href="http://www.youtube.com/watch_popup?v=Li_iCYl2ZQs&amp;amp;vq=hd720" target="_blank"&gt;Oglądaj film w rozdzielczości HD na pełnym ekranie.&lt;/a&gt;&lt;/i&gt;&amp;nbsp;&lt;/div&gt;
&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19722740-6929275232637461868?l=rpetryniak.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://rpetryniak.blogspot.com/feeds/6929275232637461868/comments/default" title="Komentarze do posta" /><link rel="replies" type="text/html" href="http://rpetryniak.blogspot.com/2012/01/aplikacja-interaktywna-w-opencv.html#comment-form" title="Komentarze (0)" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/19722740/posts/default/6929275232637461868?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/19722740/posts/default/6929275232637461868?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RafalPetryniakBlog/~3/Nzhq4bBe8VE/aplikacja-interaktywna-w-opencv.html" title="Aplikacja interaktywna w OpenCV reagującą na ruch" /><author><name>Rafał Petryniak</name><uri>https://profiles.google.com/106420849521837640393</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-ueopwOVHATs/AAAAAAAAAAI/AAAAAAAAGaw/TSrE-0eH8Zc/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://img.youtube.com/vi/Li_iCYl2ZQs/default.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://rpetryniak.blogspot.com/2012/01/aplikacja-interaktywna-w-opencv.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0ADQHc9cSp7ImA9WhdRGE8.&quot;"><id>tag:blogger.com,1999:blog-19722740.post-663011950115681230</id><published>2011-08-08T16:12:00.001+02:00</published><updated>2011-08-08T19:49:31.969+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-08-08T19:49:31.969+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="mobile" /><category scheme="http://www.blogger.com/atom/ns#" term="meego" /><category scheme="http://www.blogger.com/atom/ns#" term="Qt" /><title>Zbiór przykładowych aplikacji Qt Quick</title><content type="html">&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;Jak widać, patrząc na moje ostatnie wpisy na blogu - a raczej ich brak :-), zrobiłem sobie dłuższą przerwę od &lt;a href="http://rpetryniak.blogspot.com/search/label/meego"&gt;&lt;i&gt;MeeGo&lt;/i&gt;&lt;/a&gt; i &lt;a href="http://rpetryniak.blogspot.com/search/label/Qt"&gt;&lt;i&gt;Qt&lt;/i&gt;&lt;/a&gt;. Nie wynika to bynajmniej z utraty zainteresowania tymi dwoma technologiami, ale raczej z chronicznego braku czasu. Po rozpoczętej na początku tego roku &lt;a href="http://rpetryniak.blogspot.com/search/label/mobile"&gt;serii wpisów dotyczących systemów mobilnych&lt;/a&gt;, nadszedł czas na zapoznanie się z mocno ostatnio promowanym &lt;a href="http://qt.nokia.com/qtquick/"&gt;&lt;b&gt;Qt Quick&lt;/b&gt;&lt;/a&gt;. Nie będę jednak zbyt wiele pisał o tej technologii, bo przyznam szczerze, że nie wiele się na niej znam. Po przerobieniu jednego prostego kursu, nie będę udawał, że jestem ekspertem w tej dziedzinie :-).&lt;br /&gt;
&lt;br /&gt;
Pierwsze przymiarki do &lt;i&gt;Qt Quick&lt;/i&gt; i &lt;i&gt;QMLa&lt;/i&gt; rozpocząłem od przeszukania Internetu za gotowymi przykładami. Najwięcej jest ich oczywiście na stronie &lt;i&gt;Nokii&lt;/i&gt; i tam polecam zajrzeć. Niestety jest mały bałagan w ich lokalizacji i mimo prób ich gromadzenia na &lt;a href="http://developer.qt.nokia.com/wiki/Category:Developing_with_Qt::Qt_Quick"&gt;Wiki Qt&lt;/a&gt; lub też w &lt;a href="http://www.developer.nokia.com/Develop/Qt/Code_examples/Qt_Quick.xhtml"&gt;Portalu dla Developerów Noki&lt;/a&gt;&amp;nbsp;ciągle znajdują się one w kilku miejscach. Udało mi się nad tym zapanować tworząc odpowiednie kategorie w moich &lt;i&gt;Ulubionych&lt;/i&gt;. Oczywiście udostępniam je również Wam.&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: large;"&gt;Przykłady dołączone do oficjalnej dokumentacji:&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://doc.qt.nokia.com/latest/demos-declarative-calculator.html"&gt;Calculator&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://doc.qt.nokia.com/latest/demos-declarative-flickr.html"&gt;Flickr Mobile&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://doc.qt.nokia.com/latest/demos-declarative-minehunt.html"&gt;Minehunt&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://doc.qt.nokia.com/latest/demos-declarative-photoviewer.html"&gt;Photo Viewer&lt;/a&gt;&lt;a href="http://doc.qt.nokia.com/latest/demos-declarative-photoviewer.html"&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://doc.qt.nokia.com/latest/demos-declarative-rssnews.html"&gt;RSS News&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://doc.qt.nokia.com/latest/demos-declarative-samegame.html"&gt;Same Game&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://doc.qt.nokia.com/latest/demos-declarative-snake.html"&gt;Snake&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://doc.qt.nokia.com/latest/demos-declarative-twitter.html"&gt;Twitter Mobile&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://doc.qt.nokia.com/latest/demos-declarative-webbrowser.html"&gt;QML Web Browser&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;i&gt;Więcej przykładów na&amp;nbsp;&lt;a href="http://doc.qt.nokia.com/latest/qdeclarativeexamples.html"&gt;stronie &amp;nbsp;dokumentacji&lt;/a&gt;.&lt;/i&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;&lt;span style="font-size: large;"&gt;Przykłady opisane na Wiki Qt&lt;span style="font-size: small;"&gt; &lt;/span&gt;&lt;/span&gt;(&lt;a href="http://developer.qt.nokia.com/wiki/Category:Developing_with_Qt::Qt_Quick"&gt;link&lt;/a&gt;)&lt;span style="font-size: large;"&gt;:&lt;/span&gt;&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;a href="http://developer.qt.nokia.com/wiki/Coffee_Tweed_Demo"&gt;Coffee Tweed Demo&lt;/a&gt;&lt;a href="http://developer.qt.nokia.com/wiki/Coffee_Tweed_Demo"&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://developer.qt.nokia.com/wiki/Weather_Demo"&gt;Weather Demo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://developer.qt.nokia.com/wiki/Radio_Tuner_Demo"&gt;Radio Tuner Demo&lt;/a&gt;&lt;a href="http://developer.qt.nokia.com/wiki/Radio_Tuner_Demo"&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://developer.qt.nokia.com/wiki/In-vehicle_Infotainment_Demo"&gt;In-vehicle Infotainment Demo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://developer.qt.nokia.com/wiki/Home_Control_Demo"&gt;Home Control Demo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://developer.qt.nokia.com/wiki/Dictomania_Demo"&gt;Dictomania Demo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://developer.qt.nokia.com/wiki/Flying_Bus_Game"&gt;Flying Bus Game&lt;/a&gt;&lt;a href="http://developer.qt.nokia.com/wiki/Flying_Bus_Game"&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://developer.qt.nokia.com/wiki/How_To_Mingle_QML_Tetrominos_And_Ninjas_Zij_Lost_Tetris_Game"&gt;Tetris Game&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;span style="font-size: large;"&gt;Przykłady z portalu dla developerów Noki:&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Oficjalnie wspierane&lt;/b&gt; (&lt;a href="http://www.developer.nokia.com/Develop/Qt/Code_examples/Qt_Quick.xhtml"&gt;link&lt;/a&gt;):&lt;br /&gt;
&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://projects.developer.nokia.com/lucid"&gt;Lucid Screensaver&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://projects.developer.nokia.com/betalabsclient"&gt;Beta Labs Client&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://projects.developer.nokia.com/mediabrowser"&gt;QML Media Browser&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://projects.developer.nokia.com/mototrialracer"&gt;Moto Trial Racer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://projects.developer.nokia.com/airswype"&gt;AirSwype&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://projects.developer.nokia.com/qtquickplayground"&gt;Qt Quick Playground&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://projects.developer.nokia.com/QMLRSSReader"&gt;QML RSS Reader&lt;/a&gt;&lt;a href="https://projects.developer.nokia.com/QMLRSSReader"&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://projects.developer.nokia.com/qmlsudokumaster"&gt;Sudokumaster Qt Quick&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://projects.developer.nokia.com/guitartuner"&gt;Guitar Tuner&lt;/a&gt;&lt;a href="https://projects.developer.nokia.com/guitartuner"&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://projects.developer.nokia.com/quickhit"&gt;QuickHit&lt;/a&gt;&lt;a href="https://projects.developer.nokia.com/quickhit"&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://projects.developer.nokia.com/qtbubblelevel"&gt;Qt Bubble Level&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://projects.developer.nokia.com/turntable"&gt;DJ Turntable&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://projects.developer.nokia.com/compass"&gt;Compass&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://projects.developer.nokia.com/wwdaemon"&gt;WhoWhere Daemon&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://projects.developer.nokia.com/QMLRestaurantApp"&gt;QML RestaurantApp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://projects.developer.nokia.com/qmultiwinexample"&gt;QMultiWinExample&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;div&gt;&lt;b&gt;Rozwijane przez społeczność&lt;/b&gt; (&lt;a href="http://www.developer.nokia.com/Develop/Qt/Code_examples/Qt_Quick.xhtml"&gt;link&lt;/a&gt;) - wybrałem te, które wizualnie zrobiły na mnie największe wrażenie:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://projects.developer.nokia.com/icthub"&gt;ICT Academy Hub&lt;/a&gt;&lt;/li&gt;
&lt;ul&gt;&lt;li&gt;Egg Hunter&lt;/li&gt;
&lt;li&gt;Submariner&lt;/li&gt;
&lt;li&gt;Submariner&lt;/li&gt;
&lt;/ul&gt;&lt;li&gt;&lt;a href="https://projects.developer.nokia.com/gNewsReader"&gt;gNewsReader&lt;/a&gt;&lt;a href="https://projects.developer.nokia.com/gNewsReader"&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://projects.developer.nokia.com/qtouchandlearn"&gt;Touch'n'learn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://projects.developer.nokia.com/SystemInfo"&gt;SystemInfo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://projects.developer.nokia.com/m3uplayer"&gt;m3uplayer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://projects.developer.nokia.com/nfcchat"&gt;Nfc Chat&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://projects.developer.nokia.com/battleships"&gt;Battleships&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://projects.developer.nokia.com/EvidenceHunt"&gt;EvidenceHunt Game&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://projects.developer.nokia.com/demine"&gt;Demine&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://projects.developer.nokia.com/butaca"&gt;Butaca&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://projects.developer.nokia.com/MeasureMee"&gt;MeasureMee&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://projects.developer.nokia.com/weeklyplanner"&gt;QML Weekly Planner&lt;/a&gt;&lt;a href="https://projects.developer.nokia.com/weeklyplanner"&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://projects.developer.nokia.com/meetodo"&gt;MeeToDo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://projects.developer.nokia.com/kasvopus"&gt;Kasvopus&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://projects.developer.nokia.com/qmlbounce"&gt;QML Bounce&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://projects.developer.nokia.com/qmlbox2ddemo"&gt;QML Box2D demo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://projects.developer.nokia.com/colibri"&gt;Qt Quick Colibri&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://projects.developer.nokia.com/ShoppingList"&gt;ShoppingList&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://projects.developer.nokia.com/mirrorhouse"&gt;MirrorHouse&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://projects.developer.nokia.com/eb_media_gallery"&gt;EB Media Gallery Demo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://projects.developer.nokia.com/QtQuickTwitterExample"&gt;Qt Quick Twitter Example&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://projects.developer.nokia.com/WaterBubble"&gt;Water Bubble&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://projects.developer.nokia.com/qwhatser"&gt;Whatser&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://projects.developer.nokia.com/hitthemonkey2"&gt;Hit the Monkey 2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://projects.developer.nokia.com/QtQuickColouringBook"&gt;Qt Quick Colouring Book&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://projects.developer.nokia.com/doodledrive"&gt;DoodleDrive&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://projects.developer.nokia.com/naijanimi"&gt;Naijanimi SMS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://projects.developer.nokia.com/wordmaster"&gt;WordMaster&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://projects.developer.nokia.com/flake_weather"&gt;Flake Weather&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://projects.developer.nokia.com/PAGADI"&gt;Nu, pagadi!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://projects.developer.nokia.com/qmlbites"&gt;QML Bites&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;span style="font-size: large;"&gt;Wiki dla społeczności Noki&lt;/span&gt; (&lt;a href="http://www.developer.nokia.com/Community/Wiki/Category:Qt_Quick"&gt;link&lt;/a&gt;)&lt;span style="font-size: large;"&gt;:&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.developer.nokia.com/Community/Wiki/A_QML_Memory_Game_Tutorial"&gt;A QML Memory Game Tutorial&lt;/a&gt;&lt;a href="http://www.developer.nokia.com/Community/Wiki/A_QML_Memory_Game_Tutorial"&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.developer.nokia.com/Community/Wiki/Bubble_Kid_QML_game"&gt;Bubble Kid QML game&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.developer.nokia.com/Community/Wiki/Building_a_CoverFlow_component_with_QML"&gt;Building a CoverFlow component with QML&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.developer.nokia.com/Community/Wiki/Implementing_a_simple_View_Manager_with_QML"&gt;Implementing a simple View Manager with QML&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.developer.nokia.com/Community/Wiki/Custom_QML_Component:_Website_Thumbnails"&gt;Custom QML Component: Website Thumbnails&lt;/a&gt;&lt;a href="http://www.google.com/url?q=http%3A%2F%2Fwww.developer.nokia.com%2FCommunity%2FWiki%2FCustom_QML_Component%3A_Website_Thumbnails&amp;amp;sa=D&amp;amp;sntz=1&amp;amp;usg=AFrqEzcVVoCuQiuG3aQV9i4k9-wVbHYLuw" style="color: #0033cc; text-decoration: underline;"&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.developer.nokia.com/Community/Wiki/Can_QtQuick_create_a_Windows_Phone_Hub"&gt;Can QtQuick create a Windows Phone Hub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;&lt;/div&gt;&lt;span style="font-size: large;"&gt;Inne przykłady znalezione na stronie Qt:&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://developer.qt.nokia.com/wiki/Towers_lasers_and_spacecrafts_example"&gt;Towers lasers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.developer.nokia.com/Community/Wiki/QmlWebMapsLocation"&gt;QmlWebMapsLocation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;b&gt;Kursy i poradniki pokazujące jak coś zrobić:&lt;/b&gt;&lt;/div&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://developer.qt.nokia.com/wiki/Qt_Quick_Carousel"&gt;Obracające się menu&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://developer.qt.nokia.com/wiki/Qt_Quick_Image_Viewer"&gt;Płynne przewijanie obrazów&lt;/a&gt;&lt;a href="http://developer.qt.nokia.com/wiki/Qt_Quick_Image_Viewer"&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://developer.qt.nokia.com/wiki/Drag_and_Drop_within_a_GridView"&gt;Przeciąganie i opuszczanie elementów na siatce:&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;b&gt;Repozytoria:&lt;/b&gt;&lt;br /&gt;
&lt;ul style="text-align: left;"&gt;&lt;li&gt;&lt;a href="https://www.gitorious.org/qt-training"&gt;https://www.gitorious.org/qt-training&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://gitorious.org/ofi-labs/x2"&gt;http://gitorious.org/ofi-labs/x2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://qt.gitorious.org/qt-labs/mobile-demos"&gt;http://qt.gitorious.org/qt-labs/mobile-demos&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://qt.gitorious.org/qt-labs/graphics-dojo"&gt;http://qt.gitorious.org/qt-labs/graphics-dojo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://gitorious.org/search?q=qml"&gt;https://gitorious.org/search?q=qml&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://gitorious.org/search?q=category%3Aqml"&gt;https://gitorious.org/search?q=category%3Aqml&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;b&gt;Przykłady i projekty społeczności:&lt;/b&gt;&lt;br /&gt;
&lt;ul style="text-align: left;"&gt;&lt;li&gt;&lt;a href="http://openbossa.indt.org/canola2/index.html"&gt;Canola Media Center&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;Patrząc na tą listę nie wiem czy udało mi się znaleźć dużo, czy mało przykładów aplikacji zaimplementowanych z użyciem &lt;i&gt;Qt Quick. &lt;/i&gt;Dla osób raczkujących w tej technologi, tak jak ja, jest ich jednak w zupełności wystarczająco na start.&lt;br /&gt;
&lt;br /&gt;
&lt;ul style="text-align: left;"&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19722740-663011950115681230?l=rpetryniak.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://rpetryniak.blogspot.com/feeds/663011950115681230/comments/default" title="Komentarze do posta" /><link rel="replies" type="text/html" href="http://rpetryniak.blogspot.com/2011/08/zbior-przykadowych-aplikacji-qt-quick.html#comment-form" title="Komentarze (0)" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/19722740/posts/default/663011950115681230?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/19722740/posts/default/663011950115681230?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RafalPetryniakBlog/~3/qERfcjb61EA/zbior-przykadowych-aplikacji-qt-quick.html" title="Zbiór przykładowych aplikacji Qt Quick" /><author><name>Rafał Petryniak</name><uri>https://profiles.google.com/106420849521837640393</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-ueopwOVHATs/AAAAAAAAAAI/AAAAAAAAGaw/TSrE-0eH8Zc/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://rpetryniak.blogspot.com/2011/08/zbior-przykadowych-aplikacji-qt-quick.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0IAQX4-eSp7ImA9WhdSFk8.&quot;"><id>tag:blogger.com,1999:blog-19722740.post-8421720531026414938</id><published>2011-07-25T23:32:00.000+02:00</published><updated>2011-07-25T23:32:20.051+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-07-25T23:32:20.051+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="systemy interaktywne" /><category scheme="http://www.blogger.com/atom/ns#" term="książki" /><title>"Generative art" teraz w moim plecaku</title><content type="html">&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;Nareszcie przyszła druga zamówione przez mnie książka w &lt;i&gt;Amazon&lt;/i&gt;. Czekałem na nią długo - ok. 2 miesiące. Na szczęście w tym czasie spokojnie mogłem przejrzeć "&lt;a href="http://rpetryniak.blogspot.com/2011/06/formcode-w-mojej-biblioteczce.html"&gt;Form+Code&lt;/a&gt;". &lt;br /&gt;
&lt;br /&gt;
Pierwsze moje wrażenie po otwarciu "&lt;i&gt;&lt;b&gt;Generative art&lt;/b&gt;&lt;/i&gt;" było takie: "to nie tak miało być! spodziewałem się czegoś innego!". Moje lekkie rozczarowanie wynikało po prostu stąd, że po obejrzeniu przykładowego rozdziału, który jest dostępny na &lt;a href="http://zenbullets.com/blog/?page_id=799"&gt;stronie autora książki&lt;/a&gt; &lt;i&gt;&lt;b&gt;Matta Pearsona&lt;/b&gt;&lt;/i&gt; (podaje link, aby było szybciej: &lt;a href="http://www.manning.com/pearson/GenArt-Sample-Chapter-1.pdf"&gt;Rozdział 1&lt;/a&gt;) spodziewałem się w pełni ilustrowanej książki, coś w rodzaju katalogu projektów i opisu dobrych praktyk.&lt;br /&gt;
&lt;br /&gt;
Na szczęście, to było tylko pierwsze i jak się okazało powierzchowne wrażenie. No bo jak budować opinie na temat książki przeglądając jedynie parę stron. Wystarczy poświecić jej trochę więcej czasu, aby dostrzec, że jest ona pełna opisów dobrych praktyk, zawiera naprawdę sporo wartościowych przykładów i pokazuje krok po kroku coraz bardziej zaawansowane techniki generowania&amp;nbsp; ilustracji komputerowych. &lt;br /&gt;
&lt;br /&gt;
Więcej nie zdradzam. Zachęcam do przejrzenia :-)&lt;br /&gt;
&lt;br /&gt;
I jeszcze jedna dobra wiadomość: po zakupie książki &lt;i&gt;ebooka&lt;/i&gt; dostajemy gratis :-D.&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-fG_sBCarvz0/Ti3gOdX6G7I/AAAAAAAAGR0/H4yHfJBH2r4/s1600/book-generative_art-pearson.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="400" src="http://4.bp.blogspot.com/-fG_sBCarvz0/Ti3gOdX6G7I/AAAAAAAAGR0/H4yHfJBH2r4/s400/book-generative_art-pearson.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19722740-8421720531026414938?l=rpetryniak.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://rpetryniak.blogspot.com/feeds/8421720531026414938/comments/default" title="Komentarze do posta" /><link rel="replies" type="text/html" href="http://rpetryniak.blogspot.com/2011/07/generative-art-teraz-w-moim-plecaku.html#comment-form" title="Komentarze (2)" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/19722740/posts/default/8421720531026414938?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/19722740/posts/default/8421720531026414938?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RafalPetryniakBlog/~3/852K8mzwlR0/generative-art-teraz-w-moim-plecaku.html" title="&quot;Generative art&quot; teraz w moim plecaku" /><author><name>Rafał Petryniak</name><uri>https://profiles.google.com/106420849521837640393</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-ueopwOVHATs/AAAAAAAAAAI/AAAAAAAAGaw/TSrE-0eH8Zc/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/-fG_sBCarvz0/Ti3gOdX6G7I/AAAAAAAAGR0/H4yHfJBH2r4/s72-c/book-generative_art-pearson.png" height="72" width="72" /><thr:total>2</thr:total><feedburner:origLink>http://rpetryniak.blogspot.com/2011/07/generative-art-teraz-w-moim-plecaku.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkYNQ3Y7eyp7ImA9WhdTFUk.&quot;"><id>tag:blogger.com,1999:blog-19722740.post-1214356443583161799</id><published>2011-07-12T23:58:00.001+02:00</published><updated>2011-07-13T11:09:52.803+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-07-13T11:09:52.803+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="google" /><title>Google Matrix</title><content type="html">Wszystko wskazuje na to, że &lt;i&gt;Google&lt;/i&gt; wie o mnie wszystko. Nie tylko to z kim koresponduję, to o czym wtedy piszę, to czego szukam w Internecie i komu robię fotki wakacjach.&lt;br /&gt;
&lt;br /&gt;
Wie również z jakiego systemu korzystam i (o zgrozo) z jakiej przeglądarki nie korzystam - a wg Google powinienem ;-)&lt;br /&gt;
&lt;br /&gt;
Najlepszym przykładem tego o czym właśnie piszę, może być reklama jaką dzisiaj&amp;nbsp;zaserwował mi &lt;i&gt;Google&lt;/i&gt; w swoim &lt;i&gt;czytniku RSSów&lt;/i&gt;:&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-qf1UIA4sy48/ThzCmQyG-mI/AAAAAAAAGKY/7n7hOPPPpAA/s1600/google_matrix.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-qf1UIA4sy48/ThzCmQyG-mI/AAAAAAAAGKY/7n7hOPPPpAA/s1600/google_matrix.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;
Czyżby nadchodził Google Matrix?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19722740-1214356443583161799?l=rpetryniak.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://rpetryniak.blogspot.com/feeds/1214356443583161799/comments/default" title="Komentarze do posta" /><link rel="replies" type="text/html" href="http://rpetryniak.blogspot.com/2011/07/google-matrix.html#comment-form" title="Komentarze (0)" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/19722740/posts/default/1214356443583161799?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/19722740/posts/default/1214356443583161799?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RafalPetryniakBlog/~3/kOzhdONvdOs/google-matrix.html" title="Google Matrix" /><author><name>Rafał Petryniak</name><uri>https://profiles.google.com/106420849521837640393</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-ueopwOVHATs/AAAAAAAAAAI/AAAAAAAAGaw/TSrE-0eH8Zc/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-qf1UIA4sy48/ThzCmQyG-mI/AAAAAAAAGKY/7n7hOPPPpAA/s72-c/google_matrix.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://rpetryniak.blogspot.com/2011/07/google-matrix.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0IDRX47fip7ImA9WhdSFk8.&quot;"><id>tag:blogger.com,1999:blog-19722740.post-7770673545452081786</id><published>2011-06-13T09:38:00.000+02:00</published><updated>2011-07-25T23:32:54.006+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-07-25T23:32:54.006+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="systemy interaktywne" /><category scheme="http://www.blogger.com/atom/ns#" term="książki" /><title>"Form+Code" w mojej biblioteczce</title><content type="html">&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;Po kilku tygodniach czekania w końcu doszła do mnie nowa książka. "&lt;i&gt;&lt;b&gt;Form+Code&lt;/b&gt;&lt;/i&gt;" zamówiłem jakiś czas temu przez &lt;i&gt;Amazon&lt;/i&gt; razem z innym tytułem, o którym napiszę jaki mi go prześlą (ma być pod koniec czerwca, bo na razie nie mają go na stanie). Książka, która do mnie dotarła kilka dni temu, tak jak przewidywałem, nie jest za bardzo techniczno - informatyczna. Zawiera ona za to wiele opisów wdrożeń i instalacji światowej czołówki artystów zajmujących się sztuką generowaną (&lt;i&gt;Generative Art&lt;/i&gt;) i kreatywnym kodowaniem (&lt;i&gt;Creative Coding&lt;/i&gt;). Na szczęści książka zawiera również algorytmiczny opis kilkunastu ciekawych efektów, dzięki czemu można trochę podejrzeć jakich metod i narzędzi używają najlepsi w branży :-)&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-PlQv7dI_Pgo/Te0qqVAmYWI/AAAAAAAAGEQ/arUAMCHyy-E/s1600/form_plus_code.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="300" src="http://4.bp.blogspot.com/-PlQv7dI_Pgo/Te0qqVAmYWI/AAAAAAAAGEQ/arUAMCHyy-E/s400/form_plus_code.jpg" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
Bardzo cennym uzupełnieniem książki jest również obszerna &lt;b&gt;&lt;a href="http://formandcode.com/"&gt;strona internetowa&lt;/a&gt;&lt;/b&gt; jej poświęcona. Można na niej zobaczyć niektóre strony z książki - jest ona głównie ilustrowana więc jest co oglądać, przejrzeć spis treści, a co najważniejsze pobrać przykładowe programy dołączone do książki.&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://formandcode.com/" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="32" src="http://formandcode.com/_media/title.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
Polecam!&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19722740-7770673545452081786?l=rpetryniak.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://rpetryniak.blogspot.com/feeds/7770673545452081786/comments/default" title="Komentarze do posta" /><link rel="replies" type="text/html" href="http://rpetryniak.blogspot.com/2011/06/formcode-w-mojej-biblioteczce.html#comment-form" title="Komentarze (0)" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/19722740/posts/default/7770673545452081786?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/19722740/posts/default/7770673545452081786?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RafalPetryniakBlog/~3/v5m_tQAm6w8/formcode-w-mojej-biblioteczce.html" title="&quot;Form+Code&quot; w mojej biblioteczce" /><author><name>Rafał Petryniak</name><uri>https://profiles.google.com/106420849521837640393</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-ueopwOVHATs/AAAAAAAAAAI/AAAAAAAAGaw/TSrE-0eH8Zc/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/-PlQv7dI_Pgo/Te0qqVAmYWI/AAAAAAAAGEQ/arUAMCHyy-E/s72-c/form_plus_code.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://rpetryniak.blogspot.com/2011/06/formcode-w-mojej-biblioteczce.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0cNQHw5eSp7ImA9WhZWFUU.&quot;"><id>tag:blogger.com,1999:blog-19722740.post-3197848506206292746</id><published>2011-05-16T22:59:00.002+02:00</published><updated>2011-05-16T23:24:51.221+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-05-16T23:24:51.221+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="otwarty kod" /><category scheme="http://www.blogger.com/atom/ns#" term="systemy interaktywne" /><category scheme="http://www.blogger.com/atom/ns#" term="OpenCV" /><title>OpenCV - obsługa klawiatury i myszki</title><content type="html">&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;&lt;table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; margin-left: 1em; text-align: right;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="https://github.com/rpetryniak/OpenCv-Interactive-Apps-And-Examples/tree/master/InteractiveAppTutorial/InteractiveAppTutorial_4" imageanchor="1" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://riad.pk.edu.pl/%7Erpetryniak/website_resources/images/logo/github-logo1.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;&lt;a href="https://github.com/rpetryniak/OpenCv-Interactive-Apps-And-Examples/tree/master/InteractiveAppTutorial/InteractiveAppTutorial_4"&gt;Pełny kod źródłowy&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;Kontynuując rozpoczęty ponad miesiąc temu cykl wpisów dotyczących pisania aplikacji interaktywnych nadszedł czas na wprowadzenie kolejnego elementu do wcześniej &lt;a href="http://rpetryniak.blogspot.com/2011/04/poprawiony-szkielet-aplikacji.html"&gt;zaproponowanego szablonu&lt;/a&gt;. Dzisiaj zostanie omówiona zasadnicza kwestia pozwalająca na wprowadzenie przynajmniej podstawowej interakcji do programu: &lt;u&gt;obsługa klawiatury i myszy&lt;/u&gt;. Oczywiście dla każdego programisty naturalnym jest to, że program z definicji coś takiego posiada, tzn. że możemy klikać na przyciski, przesuwać suwaki, wybierać zakładki i wpisywać tekst do formularzy. Jednak w przypadku &lt;i&gt;OpenCV&lt;/i&gt;, należy pamiętać, że jest to biblioteka głównie do przetwarzania obrazu i chociaż obsługa klawiatury i myszy jest dostępna, to nie jest ona widoczna na pierwszy rzut oka.&lt;br /&gt;
&lt;br /&gt;
W tym wpisie poza omówieniem mechanizmów &lt;i&gt;API&lt;/i&gt; do obsługi klawiatury i myszy, zostanie dodatkowo rozszerzony omawiany we wcześniejszych wpisach przykład z kulkami. Zachęcam również do samodzielnych testów i modyfikacji udostępnionego kodu.&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: large;"&gt;Obsługa zdarzeń myszy&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Myszka w &lt;i&gt;OpenCV&lt;/i&gt; jest w pełni obsługiwana za pomocą modułu &lt;b&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;highgui&lt;/span&gt;&lt;/b&gt;, który jest również odpowiedzialny za wyświetlanie obrazków. Obsługę taką możemy włączyć za pomocą funkcji &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;cvSetMouseCallback&lt;/span&gt;, w której przywiązujemy do danego okienka funkcję obsługującą zdarzenia myszy. Dodatkowo, ponieważ jest to funkcja globalna, a nie lokalna naszej klasy &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;MainApp&lt;/span&gt;, należy do niej przekazać wskaźnik do aktualnego obiektu. Dzięki temu będziemy mieć dostęp do jego funkcji składowych. Podsumowując: należy dodać do funkcji &lt;i&gt;MainApp::run()&lt;/i&gt;&lt;b&gt; &lt;/b&gt;następującą linijkę:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint lang-cpp notranslate"&gt;cvSetMouseCallback(win_canvas, mouse_callback, this);&lt;/pre&gt;&lt;br /&gt;
Drugi parametr tej funkcji jest wskaźnikiem do właściwej funkcji obsługującej myszkę. Funkcja ta odbiera nie tylko zdarzenie jakie wystąpiło (naciśnięcie i zwolnienie klawisza, podwójny klik, przesunięcie myszki), ale również bieżące współrzędne wskaźnika myszki. &lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint lang-cpp notranslate"&gt;void mouse_callback(int event, int x, int y, int flags, void* param)
{
  MainApp *app = ((MainApp *)param);
  switch (event) {
    case  CV_EVENT_LBUTTONDBLCLK:
      app-&amp;gt;mouseDoubleClick(x,y,APP_MOUSE_LEFT);   break;
    case  CV_EVENT_RBUTTONDBLCLK:
      app-&amp;gt;mouseDoubleClick(x,y,APP_MOUSE_RIGHT);  break;
    case  CV_EVENT_MBUTTONDBLCLK:
      app-&amp;gt;mouseDoubleClick(x,y,APP_MOUSE_MIDDLE); break;
    case  CV_EVENT_LBUTTONDOWN:
      app-&amp;gt;mousePressed(x,y,APP_MOUSE_LEFT);       break;
    case  CV_EVENT_RBUTTONDOWN:
      app-&amp;gt;mousePressed(x,y,APP_MOUSE_RIGHT);      break;
    case  CV_EVENT_MBUTTONDOWN:
      app-&amp;gt;mousePressed(x,y,APP_MOUSE_MIDDLE);     break;
    case  CV_EVENT_LBUTTONUP:
      app-&amp;gt;mouseReleased(x,y,APP_MOUSE_LEFT);      break;
    case  CV_EVENT_RBUTTONUP:
      app-&amp;gt;mouseReleased(x,y,APP_MOUSE_RIGHT);     break;
    case  CV_EVENT_MBUTTONUP:
      app-&amp;gt;mouseReleased(x,y,APP_MOUSE_MIDDLE);    break;
    case  CV_EVENT_MOUSEMOVE:
      app-&amp;gt;mouseMoved(x,y);                        break;
  }
}&lt;/pre&gt;&lt;br /&gt;
Oczywiście w tym miejscu można już zaprogramować co ma się wydarzyć po  wystąpieniu konkretnego zdarzenia, ale proponuję przekazać podejmowanie tej  decyzji do wnętrza klasy, do odpowiednich funkcji. Oto one:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint lang-cpp notranslate"&gt;void MainApp::mouseMoved(int mouseX, int mouseY ){
  if (m_mousePressed) mouseDragged(mouseX, mouseY);
}

void MainApp::mouseDragged(int mouseX, int mouseY){
}

void MainApp::mousePressed(int mouseX, int mouseY, int button){
  m_mousePressed = true;
}

void MainApp::mouseReleased(int mouseX, int mouseY, int button){
  m_mousePressed = false;
}

void MainApp::mouseDoubleClick(int mouseX, int mouseY, int button){
}&lt;/pre&gt;&lt;br /&gt;
Jak widać nie ma tutaj nic szczególnego - kilka pustych funkcji. Czekają one po prostu na oprogramowanie przez użytkownika, a ich treść zależy od tego co w danym momencie chcemy osiągnąć. Na końcu wpisu zostanie podany przykład jak za pomocą kliknięcia myszką w element usunąć go z ekranu, więc polecam doczytać do końca :-).&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: large;"&gt;Obsługa zdarzeń klawiatury&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Z klawiaturą mamy już dużo łatwiej, aniżeli z myszką. Można zupełnie obejść się bez dodatkowych funkcji i wszystko zaprogramować w ciele funkcji, która zawiera pętlę główną programu. Wystarczy w tym celu skorzystać z funkcji &lt;i&gt;cvWaitKey(int)&lt;/i&gt;, aby sprawdzić czy użytkownik wcisnął jakiś klawisz. &lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint lang-cpp notranslate"&gt;int key;
while(1) {
  key = cvWaitKey(DELAY);  // wait for keyboard input
  if (key == 'q') break;   // 'q' pressed, quit the program
  if (key != -1 ) keyPressed(key);

  update();
  draw();
  
  imshow(win_canvas, canvas);
}&lt;/pre&gt;&lt;br /&gt;
Podejście to pomimo tego, że poprawne, może niepotrzebnie wprowadzić nam zamieszanie nadmiarem kodu w ważnym miejscu programu. Polecam zatem wprowadzić dodatkową funkcję, która będzie zajmowała się wyłącznie reagowaniem na zdarzenia klawiatury. Jej deklaracja jest następująca:&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;/b&gt;&lt;br /&gt;
&lt;pre class="prettyprint lang-cpp notranslate"&gt;void MainApp::keyPressed(int key){

  switch (key){
    case ' ':
      pauseBallsMove = !pauseBallsMove;
      break;
  }
}&lt;/pre&gt;&lt;br /&gt;
Patrząc na tą funkcję widać, że została zdefiniowana akcja, która wydarzy się po wciśnięciu przez użytkownika &lt;i&gt;spacji&lt;/i&gt;. Nie dzieje się tutaj nic więcej, aniżeli prosta negacja zmiennej logicznej &lt;i&gt;pauseBallsMove&lt;/i&gt;. Zmienna ta może się przydać np. do zatrzymania ruchu elementów w naszym przykładowym programie:&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;MainApp::update() &lt;/b&gt;&lt;br /&gt;
&lt;pre class="prettyprint lang-cpp notranslate"&gt;if (!pauseBallsMove) {
  for (int i = 0; i &amp;lt; myBall.size(); i++) {
    myBall[i].update();
  }
}&lt;/pre&gt;&lt;br /&gt;
&lt;span style="font-size: large;"&gt;Przykładowa aplikacja&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
A teraz obiecany przykład :-) Nie zawiera on szczególnie wiele kodu, ale efekt jaki pozwala osiągnąć wydaje się całkiem interesujący. Na początek polecam dodać dodatkowe polecenia obsługujące zdarzenie naciśnięcia klawisza &lt;b style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;'a'&lt;/b&gt; i &lt;b&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;'d'&lt;/span&gt;&lt;/b&gt;. Naciśniecie pierwszej literki będzie powodować dodanie kolejnych kulek na ekranie, natomiast naciśnięcie drugiej zmniejszenie ich liczny.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint lang-cpp notranslate"&gt;case 'a':
  myBall.push_back( Ball(&amp;amp;canvas) );
  break;
case 'd':
  if (myBall.size()&amp;gt;=1) myBall.pop_back();
  break;&lt;/pre&gt;&lt;br /&gt;
Kolejną zmianą jaką można wprowadzić jest dodanie kilku linii kodu, reagujących na klikniecie myszką. Uzupełniamy ciało funkcji &lt;i&gt;mousePressed&lt;/i&gt; następującym kodem:&lt;br /&gt;
&lt;b&gt;&lt;br /&gt;
&lt;/b&gt;&lt;br /&gt;
&lt;pre class="prettyprint lang-cpp notranslate"&gt;for(int i=0; i &amp;lt; myBall.size(); i++) {
  if(myBall[i].checkMouseOver(mouseX, mouseY)) {
    myBall[i].decrementLives();

    if(myBall[i].isEndLive()) myBall.erase(myBall.begin()+i);
  }
}&lt;/pre&gt;&lt;br /&gt;
Teraz jeszcze wystarczy dodać kilka nowych funkcji do klasy &lt;i&gt;Ball&lt;/i&gt;:&lt;br /&gt;
&lt;b&gt;&lt;br /&gt;
&lt;/b&gt;&lt;br /&gt;
&lt;pre class="prettyprint lang-cpp notranslate"&gt;bool Ball::checkMouseOver(int _mouseX, int _mouseY) {
  bool mouseIsOver = false;

  if ( dist(_mouseX,_mouseY,x,y) &amp;lt; dim ) mouseIsOver = true;

  return mouseIsOver;
}

void Ball::decrementLives() {
  lives--;
}

bool Ball::isEndLive() {
  return (lives &amp;lt;= 0);
}
&lt;/pre&gt;&lt;br /&gt;
i chyba nie trudno się domyślić jaki w ten sposób efekt możemy uzyskać :-)&lt;br /&gt;
&lt;br /&gt;
Dla osób zniecierpliwionych lub takich, które nie mają czasu na samodzielną kompilację przykładu, przygotowałem krótki filmik pokazujący efekty wprowadzenia obsługi klawiatury i myszki do omawianej aplikacji:&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: center;"&gt;&lt;iframe allowfullscreen="" frameborder="0" height="314" src="http://www.youtube.com/embed/Ui4h_AGoohc" width="500"&gt;&lt;/iframe&gt;&lt;br /&gt;
&lt;a href="http://www.youtube.com/watch_popup?v=Ui4h_AGoohc&amp;amp;vq=hd720" target="_blank"&gt;&lt;i&gt;Oglądaj film w rozdzielczości HD na pełnym ekranie.&lt;/i&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19722740-3197848506206292746?l=rpetryniak.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://rpetryniak.blogspot.com/feeds/3197848506206292746/comments/default" title="Komentarze do posta" /><link rel="replies" type="text/html" href="http://rpetryniak.blogspot.com/2011/05/opencv-obsuga-klawiatury-i-myszki.html#comment-form" title="Komentarze (0)" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/19722740/posts/default/3197848506206292746?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/19722740/posts/default/3197848506206292746?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RafalPetryniakBlog/~3/NaCSnzvkEt4/opencv-obsuga-klawiatury-i-myszki.html" title="OpenCV - obsługa klawiatury i myszki" /><author><name>Rafał Petryniak</name><uri>https://profiles.google.com/106420849521837640393</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-ueopwOVHATs/AAAAAAAAAAI/AAAAAAAAGaw/TSrE-0eH8Zc/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://img.youtube.com/vi/Ui4h_AGoohc/default.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://rpetryniak.blogspot.com/2011/05/opencv-obsuga-klawiatury-i-myszki.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0cNQHw5eSp7ImA9WhZWFUU.&quot;"><id>tag:blogger.com,1999:blog-19722740.post-1646513618463277897</id><published>2011-04-19T09:19:00.000+02:00</published><updated>2011-05-16T23:24:51.221+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-05-16T23:24:51.221+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="otwarty kod" /><category scheme="http://www.blogger.com/atom/ns#" term="systemy interaktywne" /><category scheme="http://www.blogger.com/atom/ns#" term="OpenCV" /><title>Repozytorium dla przykładów OpenCV na GitHub</title><content type="html">W ostatnim czasie na blogu &lt;a href="http://rpetryniak.blogspot.com/search/label/OpenCV"&gt;pojawiło się kilka wpisów&lt;/a&gt; o &lt;i&gt;OpenCV&lt;/i&gt;. Wiele z nich zawierało przykładowy kod źródłowy, który wklejałem we fragmentach, aby nie wydłużać samych postów. Były to głównie kluczowe fragmenty opisywanych programów i nie zawierały one najczęściej początku i końca pliku. Wiem, że nie jest to żaden kłopot dla osób, które miały do czynienia z &lt;i&gt;OpenCV&lt;/i&gt;, ale dla początkującego użytkownika może to być mały problem. Łatwo przecież zrobić drobny błąd, literówkę lub coś przeoczyć, a trudniej to później znaleźć. W związku z tym utworzyłem publiczne repozytorium kodu źródłowego &lt;i&gt;GitHub&lt;/i&gt;, do którego wypchnąłem (&lt;i&gt;push&lt;/i&gt; - w terminologii &lt;i&gt;Git&lt;/i&gt;) opracowane do tej pory przykłady. Do repozytorium można przejść klikając w poniższy obrazek.&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="https://github.com/rpetryniak/OpenCv-Interactive-Apps-And-Examples" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_AeFiJN9phoM/Ta0zxds0HGI/AAAAAAAAGBw/sH1ntbh9WT8/opencv-nowe_repozytorium_na_github.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19722740-1646513618463277897?l=rpetryniak.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://rpetryniak.blogspot.com/feeds/1646513618463277897/comments/default" title="Komentarze do posta" /><link rel="replies" type="text/html" href="http://rpetryniak.blogspot.com/2011/04/repozytorium-dla-przykadow-opencv-na.html#comment-form" title="Komentarze (0)" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/19722740/posts/default/1646513618463277897?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/19722740/posts/default/1646513618463277897?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RafalPetryniakBlog/~3/aS4Kf6BOBAk/repozytorium-dla-przykadow-opencv-na.html" title="Repozytorium dla przykładów OpenCV na GitHub" /><author><name>Rafał Petryniak</name><uri>https://profiles.google.com/106420849521837640393</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-ueopwOVHATs/AAAAAAAAAAI/AAAAAAAAGaw/TSrE-0eH8Zc/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_AeFiJN9phoM/Ta0zxds0HGI/AAAAAAAAGBw/sH1ntbh9WT8/s72-c/opencv-nowe_repozytorium_na_github.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://rpetryniak.blogspot.com/2011/04/repozytorium-dla-przykadow-opencv-na.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0cNQHw5eip7ImA9WhZWFUU.&quot;"><id>tag:blogger.com,1999:blog-19722740.post-3190604855970347527</id><published>2011-04-11T23:18:00.003+02:00</published><updated>2011-05-16T23:24:51.222+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-05-16T23:24:51.222+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="otwarty kod" /><category scheme="http://www.blogger.com/atom/ns#" term="systemy interaktywne" /><category scheme="http://www.blogger.com/atom/ns#" term="OpenCV" /><title>Poprawiony szkielet aplikacji interaktywnej dla OpenCV</title><content type="html">&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;&lt;table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; margin-left: 1em; text-align: right;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="https://github.com/rpetryniak/OpenCv-Interactive-Apps-And-Examples/tree/master/InteractiveAppTutorial/InteractiveAppTutorial_3" imageanchor="1" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://riad.pk.edu.pl/%7Erpetryniak/website_resources/images/logo/github-logo1.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;&lt;a href="https://github.com/rpetryniak/OpenCv-Interactive-Apps-And-Examples/tree/master/InteractiveAppTutorial/InteractiveAppTutorial_3"&gt;Pełny kod źródłowy&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;Kilka dni temu zaproponowałem na tym blogu &lt;a href="http://rpetryniak.blogspot.com/2011/04/obiektowy-szkielet-aplikacji.html"&gt;obiektowy szkielet aplikacji interaktywnej dla OpenCV&lt;/a&gt;. W dzisiejszym wpisie chciałbym pokazać jak można zrobić to jeszcze lepiej, aby kod był nie tylko bardziej obiektowy, ale również miał lepiej zorganizowaną strukturę. Pomimo tego, że przedstawiony tam schemat aplikacji całkiem nieźle się sprawdza, a kod jest w miarę czytelny, ma on kilka wad i usterek, które zapewne niejeden zaawansowany programista C++ szybko mógłby wytknąć. Oto dwie z nich:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Cały kod programu został umieszczony w jednym pliku. Dla małych projektów jest to w miarę dobre rozwiązanie, jednak przy większych aplikacjach może być uciążliwe. Umieszczanie całego kodu w jednym pliku łamie również powszechnie stosowaną zasadę umieszczania każdej klasy w osobnym pliku. Inną powszechnie znaną praktyką, która nie została tam zastosowana, jest rozdział deklaracji klasy od jej ciała i umieszczenie ich osobno w pliku nagłówkowym (*.h) i w pliku z implementacją funkcji (*.cpp).&lt;/li&gt;
&lt;li&gt;Trudno nazwać przedstawiony w poprzednim wpisie szkielet za w pełni obiektowy, jeśli znajduje się tam jedna klasa, która zawiera całą funkcjonalność aplikacji. Szczególnie problem jest widoczny w braku osobnej reprezentacji obiektowej dla znajdujących się tam kulek. Problem ten nie jest szczególnie zauważalny w przypadku istnienia jednej kulki, ale jest już odczuwalny w przypadku ich większej ilości. Wystarczy spojrzeć na funkcję&amp;nbsp;&lt;i&gt;MainApp::update()&lt;/i&gt; i spróbować sobie wyobrazić, jak&amp;nbsp;mogłaby ona wyglądać, jeśli trzeba by było zarządzać ruchem i rysowaniem np. 10 kulek. Widać wyraźnie, że coś jest tutaj nie tak i wręcz konieczne wydaje się rozszerzenie modelu obiektowego własnie o te obiekty, które są rysowane na ekranie, a które mają w miarę niezależny schemat poruszania się.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;Patrząc na te problemy postanowiłem szybko wprowadzić niezbędne poprawki, aby wyeliminować opisane niedogodności. Z jednego pliku powstało ich sześć. Dodatkowo utworzyłem klasę &lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&lt;b&gt;Ball&lt;/b&gt;&lt;/span&gt; reprezentująca ruch i wygląd kulek. Pozwoliło mi to na wprowadzenie łatwej personalizacji dla każdej kulki z osobna. Struktura obydwu klas (&lt;i&gt;MainApp&lt;/i&gt; i &lt;i&gt;Ball&lt;/i&gt;) została rozdzielona na pliki nagłówkowe i pliki z implementacją ich funkcji składowych.&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;Krótka charakterystyka szkieletu aplikacji interaktywnej OpenCV&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;interactive_app_tutorial-main.cpp&lt;/b&gt; - plik ten zawiera jedynie funkcję główną programu &lt;i&gt;main()&lt;/i&gt;, której jedynym zadaniem jest uruchomienie i wyświetlenie głównego okna aplikacji reprezentowanego przez klasę &lt;i&gt;MainApp&lt;/i&gt;. Dodatkowo na początku tego pliku inicjalizowany&amp;nbsp;jest&amp;nbsp;generator liczb losowych &lt;i&gt;OpenCV&lt;/i&gt; wartością równą liczbie milisekund, która upłynęła od ustalonej daty w przeszłości (w systemie &lt;i&gt;Linux&lt;/i&gt; jest to 1 styczeń 1970 roku).&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint lang-cpp notranslate"&gt;#include &amp;lt;opencv2/highgui/highgui.hpp&amp;gt;
#include &amp;lt;opencv2/imgproc/imgproc.hpp&amp;gt;

#include "interactive_app_tutorial-MainApp.h"

using namespace cv;

RNG rng(cvGetTickCount());

int main(int, char**)
{
  MainApp::getInstance().run();
  
  return 0;
}&lt;/pre&gt;&lt;br /&gt;
&lt;b&gt;interactive_app_tutorial-util.h&lt;/b&gt; - tutaj najlepiej umieszczać funkcje ogólnego przeznaczenia oraz funcke narzędziowe, które mogą się przydać w różnych miejscach programu. Na razie znajduje się tu jedynie funkcja zwracająca składowe koloru, dla przekazanej jako parametr liczby.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint lang-cpp notranslate"&gt;#ifndef UTIL_H
#define UTIL_H

static Scalar randomColor(RNG&amp;amp; rng)
{
  int icolor = (unsigned)rng;
  return Scalar(icolor&amp;amp;255, (icolor&amp;gt;&amp;gt;8)&amp;amp;255, (icolor&amp;gt;&amp;gt;16)&amp;amp;255);
}

#endif&lt;/pre&gt;&lt;br /&gt;
&lt;b&gt;interactive_app_tutorial-MainApp.h&lt;/b&gt; - jest to plik nagłówkowy zawierający deklarację klasy &lt;i&gt;MainApp&lt;/i&gt; i jej składowych. Na pierwszy rzut nie widać, aby coś się zmieniło względem szkieletu aplikacji opisanego w poprzednim wpisie. Jednak jak będzie to widać dalej, implementacja poszczególnych funkcji jest już zupełnie inna. Patrząc na zmienne prywatne jakie tutaj zostały zadeklarowane, można zauważyć, że klasa będzie zarządzać trzema kulkami. Jak sobie poradzić z tym ograniczeniem zostanie pokazane na końcu tego wpisu.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint lang-cpp notranslate"&gt;#ifndef MAINAPP_H
#define MAINAPP_H

#include &amp;lt;opencv2/highgui/highgui.hpp&amp;gt;
#include &amp;lt;opencv2/imgproc/imgproc.hpp&amp;gt;

#include "interactive_app_tutorial-Ball.h"

using namespace cv;

//MainApp singelton class
class MainApp
{
private:
  Mat canvas;               // Image for drawing
  Scalar bgr_color;         // Background color
  Ball *myBall_1, *myBall_2, *myBall_3;
  
public: // Some global params:
  static int DELAY;
  static int CANVAS_WIDTH;  
  static int CANVAS_HEIGHT;  
  
private:
  MainApp() {}
  MainApp(const MainApp &amp;amp;);
  MainApp&amp;amp; operator=(const MainApp&amp;amp;);
  
  void setup();   // Initial commands for setup processing
  void update();  // Commands to modify the parameters
  void draw();    // Drawing functions:
  
public:
  static MainApp&amp;amp; getInstance()
  {
    static MainApp instance;
    return instance;
  }
  
  // Main loop function with displaying image support
  // and handle mouse and keyboard events
  void run();
};

#endif&lt;/pre&gt;&lt;br /&gt;
&lt;b&gt;interactive_app_tutorial-MainApp.cpp&lt;/b&gt; - plik ten zawiera właściwą implementację funkcji zawartych w klasie &lt;i&gt;MainApp&lt;/i&gt;. Nie są one jakość szczególnie interesujące ponieważ wywołują jedynie funkcje składowe klasy &lt;i&gt;Ball&lt;/i&gt; o identycznych nazwach. &lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint lang-cpp notranslate"&gt;#include &amp;lt;opencv2/highgui/highgui.hpp&amp;gt;
#include &amp;lt;opencv2/imgproc/imgproc.hpp&amp;gt;

#include "interactive_app_tutorial-MainApp.h"

using namespace cv;

// Best place to initialize global MainApp params:
int MainApp::DELAY        = 5;
int MainApp::CANVAS_WIDTH = 500;
int MainApp::CANVAS_HEIGHT= 350;

void MainApp::run() {
  setup();
  
  const char *win_canvas = "Canvas";
  namedWindow(win_canvas, CV_WINDOW_AUTOSIZE);
  
  while (cvWaitKey(4) == -1) {
    update();
    draw();
    
    imshow(win_canvas, canvas);
    waitKey(DELAY);
  }
}

void MainApp::setup() 
{
  bgr_color = Scalar(200,200,200);
  canvas = Mat(CANVAS_HEIGHT, CANVAS_WIDTH, CV_8UC3, bgr_color);
  
  myBall_1 = new Ball(&amp;amp;canvas);
  myBall_2 = new Ball(&amp;amp;canvas);
  myBall_3 = new Ball(&amp;amp;canvas);
}

void MainApp::draw() {
  canvas = bgr_color;
  
  myBall_1-&amp;gt;draw();    
  myBall_2-&amp;gt;draw();    
  myBall_3-&amp;gt;draw();    
}

void MainApp::update() 
{
  myBall_1-&amp;gt;update();
  myBall_2-&amp;gt;update();
  myBall_3-&amp;gt;update();
}&lt;/pre&gt;&lt;br /&gt;
&lt;b&gt;interactive_app_tutorial-Ball.h&lt;/b&gt; - tak naprawdę to tutaj zaczynają się większe zmiany względem &lt;a href="http://rpetryniak.blogspot.com/2011/04/obiektowy-szkielet-aplikacji.html"&gt;poprzedniego szkieletu aplikacji&lt;/a&gt;. Plik ten zawiera deklarację nowej klasy &lt;i&gt;Ball&lt;/i&gt;, która już sama będzie dbać o swój wygląd, wyrysowanie siebie na ekranie oraz wyliczenie właściwej lokalizacji dla kolejnej iteracji. Sprawą, na którą należy tutaj zwrócić szczególną uwagą jest postać konstruktorów. Konstruktor domyślny &lt;i&gt;Ball()&lt;/i&gt; został specjalnie zablokowany, aby zachęcić (zmusić ;-)) użytkownika do korzystania z dodatkowego konstruktora, który jako parametr przyjmuje wskaźnik do struktury &lt;i&gt;cv::Mat&lt;/i&gt;,&amp;nbsp;po której będzie można rysować. Generalnie powinien być tutaj przekazywany wskaźnik do głównego obrazka z klasy &lt;i&gt;MainApp&lt;/i&gt;, na którym odbywa się rysowanie.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint lang-cpp notranslate"&gt;#ifndef BALL_H
#define BALL_H

#include &amp;lt;opencv2/highgui/highgui.hpp&amp;gt;
#include &amp;lt;opencv2/imgproc/imgproc.hpp&amp;gt;

using namespace cv;

//Ball class
class Ball 
{
private:
  Mat *canvas;
  float x, y, dim;
  float speedX, speedY;
  Scalar color;
  
  Ball();
  void setup();
  
public:
  Ball(Mat *can)
  {
    canvas = can;
    setup();
  }
  
  void update();
  void draw();
};

#endif&lt;/pre&gt;&lt;br /&gt;
&lt;b&gt;interactive_app_tutorial-Ball.cpp&lt;/b&gt; - osoby, które już wcześniej analizowały poprzedni szkielet aplikacji zapewne zauważyły, że istotna część treści funkcji &lt;i&gt;MainApp::update()&lt;/i&gt; i &lt;i&gt;MainApp::draw()&lt;/i&gt;&amp;nbsp;zostały przeniesione do funkcji o identycznych nazwach w klasie &lt;i&gt;Ball&lt;/i&gt;. Jest to najważniejsza zmiana w nowym szablonie. Teraz to każda kulka samodzielnie dba o siebie i kontroluje swoje zachowanie.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint lang-cpp notranslate"&gt;#include &amp;lt;opencv2/highgui/highgui.hpp&amp;gt;
#include &amp;lt;opencv2/imgproc/imgproc.hpp&amp;gt;

#include "interactive_app_tutorial-Ball.h"
#include "interactive_app_tutorial-MainApp.h"
#include "interactive_app_tutorial-util.h"

using namespace cv;

extern RNG rng;

void Ball::setup()
{
  x = rng.uniform(0, MainApp::CANVAS_WIDTH); // give some random positioning
  y = rng.uniform(0, MainApp::CANVAS_HEIGHT);
  speedX = rng.uniform((float)-2, (float)2); // and random speed and direction
  speedY = rng.uniform((float)-2, (float)2);
  dim    = rng.uniform(20,60);
  
  color = randomColor(rng);
}

void Ball::update() 
{
  if(x &amp;lt; 0 ){
    x = 0;
    speedX *= -1;
  } else if(x &amp;gt; MainApp::CANVAS_WIDTH){
    x = MainApp::CANVAS_WIDTH;
    speedX *= -1;
  }
  
  if(y &amp;lt; 0 ){
    y = 0;
    speedY *= -1;
  } else if(y &amp;gt; MainApp::CANVAS_HEIGHT){
    y = MainApp::CANVAS_HEIGHT;
    speedY *= -1;
  } 
  
  x+=speedX;
  y+=speedY;  
}

void Ball::draw()
{
  circle(*canvas, Point(x,y), dim, color,-1,CV_AA); 
}&lt;/pre&gt;&lt;br /&gt;
&lt;b&gt;CMakeLists.txt&lt;/b&gt; - plik ten zawiera konfigurację procesu kompilacji &lt;i&gt;CMake&lt;/i&gt; dla omówionego przykładu. Wcześniej był tylko jeden plik, teraz jest ich sześć. Aby się w tym nie pogubić warto skorzystać właśnie z &lt;i&gt;CMake&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint lang-cpp notranslate"&gt;PROJECT(OpenCvInteractiveAppsAndExamples-InteractiveAppTutorial2)

cmake_minimum_required(VERSION 2.8)

FIND_PACKAGE( OpenCV REQUIRED )

ADD_EXECUTABLE(interactive_app_tutorial_2 interactive_app_tutorial-main.cpp interactive_app_tutorial-MainApp.cpp interactive_app_tutorial-Ball.cpp)
TARGET_LINK_LIBRARIES(interactive_app_tutorial_2 ${OpenCV_LIBS})&lt;/pre&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;Drobne poprawki na koniec&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Wydawać by się mogło, ze w opisanym powyżej szkielecie aplikacji &lt;i&gt;OpenCv&lt;/i&gt; wszystko jest OK, ale jeden szczegół na dłuższą metę może okazać się bardzo uciążliwy. W tym momencie w klasie &lt;i&gt;MainApp&lt;/i&gt; zosłao z góry określone ile kulek będzie rysowane na ekranie. Trzy kulki to trochę mało. Co by było gdyby trzeba&amp;nbsp;ich&amp;nbsp;było narysować np. trzysta? Najlepiej w takiej sytuacji skorzystać z dynamicznie rozszerzanych kontenerów dostępnych w C++. Klasa &lt;i&gt;vector&lt;/i&gt; będzie w zupełności wystarczająca. Na początek warto zmienić deklarację klasy &lt;i&gt;MainApp&lt;/i&gt; usuwając z niej zmienne lokalne&amp;nbsp;&lt;i&gt;*myBall_1, *myBall_2, *myBall_3&lt;/i&gt;, a wprowadzając na to miejsce deklarację wektora&amp;nbsp;&lt;span class="Apple-style-span" style="background-color: #eeeeee; font-family: 'Courier New',Courier,monospace;"&gt;vector &amp;lt;Ball&amp;gt; myBall;&lt;/span&gt;. Ja dodatkowo wprowadziłem jeszcze jedną zmienną statyczną, która będzie regulować liczbę kulek wyświetlanych na ekranie. Po tych zmianach kod kod może wyglądać jak poniżej:&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;interactive_app_tutorial-MainApp.h&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint lang-cpp notranslate"&gt;private:
  vector &amp;lt;Ball&amp;gt; myBall;
  //...
  
public:
  static int INITIAL_BALLS_NUMBER;
  //...&lt;/pre&gt;&lt;br /&gt;
Kolejna zmiana, która należy wprowadzić to aktualizacja funkcji &lt;i&gt;setup()&lt;/i&gt;, &lt;i&gt;update()&lt;/i&gt; i &lt;i&gt;draw()&lt;/i&gt; klasy &lt;i&gt;MainApp&lt;/i&gt;. Teraz one powinny wyglądać następująco:&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;interactive_app_tutorial-MainApp.cpp&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint lang-cpp notranslate"&gt;void MainApp::setup() 
{
  bgr_color = Scalar(200,200,200);
  canvas = Mat(CANVAS_HEIGHT, CANVAS_WIDTH, CV_8UC3, bgr_color);
  
  for (int i = 0; i &amp;lt; INITIAL_BALLS_NUMBER; i++){
    myBall.push_back( Ball(&amp;amp;canvas) );
  }

}

void MainApp::draw() {
  canvas = bgr_color;
  
  for (int i = 0; i &amp;lt; myBall.size(); i++){
    myBall[i].draw();
  }  
}

void MainApp::update() 
{
  for (int i = 0; i &amp;lt; myBall.size(); i++){
    myBall[i].update();
  } 
}&lt;/pre&gt;&lt;br /&gt;
Ostatecznie aplikacja po powyższych zmianach i ustawieniu liczby kulek na 30 może dać rezultat podobny jak ten na obrazku poniżej:  &lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_AeFiJN9phoM/TaNoDygWbDI/AAAAAAAAGBI/pYkugIXp7k0/OpenCv-interactive_app_tutorial_2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_AeFiJN9phoM/TaNoDygWbDI/AAAAAAAAGBI/pYkugIXp7k0/OpenCv-interactive_app_tutorial_2.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
W miarę wolnego czasu w kolejnych wpisach będę chciał pokazać jak wprowadzić do powyższego szablonu możliwości interakcji za pomocą klawiatury i myszki oraz za pomocą ruchu zarejestrowanego kamerą.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19722740-3190604855970347527?l=rpetryniak.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://rpetryniak.blogspot.com/feeds/3190604855970347527/comments/default" title="Komentarze do posta" /><link rel="replies" type="text/html" href="http://rpetryniak.blogspot.com/2011/04/poprawiony-szkielet-aplikacji.html#comment-form" title="Komentarze (0)" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/19722740/posts/default/3190604855970347527?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/19722740/posts/default/3190604855970347527?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RafalPetryniakBlog/~3/yWx7cOegfy8/poprawiony-szkielet-aplikacji.html" title="Poprawiony szkielet aplikacji interaktywnej dla OpenCV" /><author><name>Rafał Petryniak</name><uri>https://profiles.google.com/106420849521837640393</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-ueopwOVHATs/AAAAAAAAAAI/AAAAAAAAGaw/TSrE-0eH8Zc/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_AeFiJN9phoM/TaNoDygWbDI/AAAAAAAAGBI/pYkugIXp7k0/s72-c/OpenCv-interactive_app_tutorial_2.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://rpetryniak.blogspot.com/2011/04/poprawiony-szkielet-aplikacji.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0UGRHw7cSp7ImA9WhZWFUU.&quot;"><id>tag:blogger.com,1999:blog-19722740.post-9196938830824373411</id><published>2011-04-07T23:31:00.002+02:00</published><updated>2011-05-16T23:27:05.209+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-05-16T23:27:05.209+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="otwarty kod" /><category scheme="http://www.blogger.com/atom/ns#" term="systemy interaktywne" /><category scheme="http://www.blogger.com/atom/ns#" term="OpenCV" /><title>Obiektowy szkielet aplikacji interaktywnej dla OpenCV</title><content type="html">&lt;table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; margin-left: 1em; text-align: right;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="https://github.com/rpetryniak/OpenCv-Interactive-Apps-And-Examples/tree/master/InteractiveAppTutorial/InteractiveAppTutorial_1" imageanchor="1" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://riad.pk.edu.pl/%7Erpetryniak/website_resources/images/logo/github-logo1.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;&lt;a href="https://github.com/rpetryniak/OpenCv-Interactive-Apps-And-Examples/tree/master/InteractiveAppTutorial/InteractiveAppTutorial_1"&gt;Pełny kod źródłowy&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;Biblioteka &lt;i&gt;OpenCV&lt;/i&gt; pomimo tego, że zawiera sporo konstrukcji obiektowych i pozwala pisać programy w C++, sama w sobie nie precyzuje i nie podpowiada jaką strukturę powinien mieć dobrze napisany kod programu. Wpływa to oczywiście na morale wielu programistów, którzy widząc, że można napisać kod liniowo w całości w funkcji &lt;i&gt;main&lt;/i&gt;, idą na skróty i własnie&amp;nbsp;tak&amp;nbsp;robią. Nie chciałbym tutaj nikogo szczególnie piętnować ;), ale większość przykładowych programów, które ostatnio analizowałem tak własnie jest napisana. Dotyczy to również standardowych przykładów dołączonych do biblioteki &lt;i&gt;OpenCV&lt;/i&gt;. Oczywiście tak nie musi być. Programy napisane w &lt;i&gt;OpenCV&lt;/i&gt; przy zastosowaniu podstawowych konstrukcji obiektowych mogą być nie tylko czytelniejsze dla osoby, która je pierwszy raz przegląda, ale również znacznie łatwiejsze w pielęgnacji i dalszym rozwoju dla osoby lub zespołu, który taką aplikację napisał.&lt;br /&gt;
&lt;br /&gt;
W tym wpisie chciałem się podzielić szablonem aplikacji &lt;i&gt;OpenCV&lt;/i&gt;, którego ostatnio używam. Jest to szablon, który może być szczególnie użyteczny dla aplikacji interaktywnych, w których użytkownik ma wpływ na zachowanie wyświetlanych elementów. Przygotowując ten szablon starałem&amp;nbsp;się zachować podejście znane z programowania aplikacji okienkowych, gdzie pracujemy raczej na komponentach odnoszących się do interfejsu użytkownika, a nie na wielu obiektach z mniej lub bardziej złożoną strukturą powiązań. Jak widać z analizy poniższego kodu funkcja &lt;i&gt;main&lt;/i&gt; została zredukowana do minimum, a cała logika aplikacji została przeniesiona do klasy&amp;nbsp;&lt;i&gt;MainApp&lt;/i&gt;. Klasa ta nie powinna być wielokrotnie tworzona, dlatego została ona skonstruowana w oparciu o wzorzec&amp;nbsp;S&lt;i&gt;ingelton&lt;/i&gt;, który tego pilnuje.&lt;br /&gt;
&lt;br /&gt;
Polecam teraz dokładnie przeanalizować podany szablon, a dalsze wyjaśnienia będzie można przeczytać poniżej.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint lang-cpp notranslate"&gt;#include &amp;lt;opencv2/highgui/highgui.hpp&amp;gt;
#include &amp;lt;opencv2/imgproc/imgproc.hpp&amp;gt;

using namespace cv;

//MainApp singelton class
class MainApp
{
private:
  Mat canvas;               // Image for drawing
  Scalar bgr_color;         // Background color
  int x, y, speedX, speedY; // Circle local params
  
public: // Some global params:
  static int DELAY;
  static int CANVAS_WIDTH;  
  static int CANVAS_HEIGHT;  
  
private:
  MainApp() {}
  MainApp(const MainApp &amp;amp;);
  MainApp&amp;amp; operator=(const MainApp&amp;amp;);
  
  // Initial commands for setup processing
  void setup() 
  {
    x = 0;
    y = 0;
    speedX = 1;
    speedY = 1;
    
    bgr_color = Scalar(120,235,139);
    canvas = Mat(CANVAS_HEIGHT, CANVAS_WIDTH, CV_8UC3, bgr_color);
  }
  
  // Commands to modify the parameters
  void update() 
  {
    if(x &amp;lt; 0 ){
      x = 0;
      speedX *= -1;
    } else if(x &amp;gt; CANVAS_WIDTH){
      x = CANVAS_WIDTH;
      speedX *= -1;
    }
    
    if(y &amp;lt; 0 ){
      y = 0;
      speedY *= -1;
    } else if(y &amp;gt; CANVAS_HEIGHT){
      y = CANVAS_HEIGHT;
      speedY *= -1;
    } 
    
    x+=speedX;
    y+=speedY;    
  }
  
  // Drawing functions:
  void draw() {
    canvas = bgr_color;
    circle(canvas, Point(x,y), 30, Scalar(0,255,255),-1,CV_AA);
  }
  
public:
  static MainApp&amp;amp; getInstance()
  {
    static MainApp instance;
    return instance;
  }
  
  // Main loop function with displaying image support
  // and handle mouse and keyboard events
  void run() {
    setup();

    const char *win_canvas = "Canvas";
    namedWindow(win_canvas, CV_WINDOW_AUTOSIZE);

    while (cvWaitKey(4) == -1) {
      update();
      draw();
      
      imshow(win_canvas, canvas);
      waitKey(DELAY);
    }
  }
};

// Best place to initialize global MainApp params:
int MainApp::DELAY        = 5;
int MainApp::CANVAS_WIDTH = 500;
int MainApp::CANVAS_HEIGHT= 350;

int main(int, char**)
{
  MainApp::getInstance().run();
  
  return 0;
}&lt;/pre&gt;&lt;br /&gt;
Patrząc na powyższy kod nie trudno zauważyć, że został on podzielony na kilka części. Dotyczy to szczególnie klasy &lt;i&gt;MainApp&lt;/i&gt;. Została ona podzielona na funkcje, które mają ściśle określone role:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;b&gt;run()&lt;/b&gt;&lt;/span&gt; - publicznie dostępna funkcja, która obsługuje główną pętlę programu. Program będzie się w niej wykonywał do momentu, aż użytkownik wciśnie klawisz &lt;i&gt;Escape&lt;/i&gt;. Funkcja ta nie tylko wywołuje kolejne, niżej opisane funkcje, ale również odpowiada za wyświetlanie głównego okienka programu i obsługę zdarzeń nadchodzących z klawiatury i myszki.&lt;/li&gt;
&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;b&gt;setup()&lt;/b&gt;&lt;/span&gt; - funkcja wywoływana tylko raz, na początku działania programu, której zadaniem jest inicjalizacja zmiennych lokalnych i utworzenie obrazka, na którym będą rysowane pozostałe elementy.&lt;/li&gt;
&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;b&gt;update()&lt;/b&gt;&lt;/span&gt; - funkcja modyfikująca wybrane parametry działania programu. Tak naprawdę to tutaj powinna być zapisana główna logika działania programu.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;b&gt;draw()&lt;/b&gt;&lt;/span&gt; - zawiera wszystkie operacje rysowania na głównej scenie programu.&lt;/li&gt;
&lt;/ul&gt;Aby jeszcze dokładniej prześledzić organizację kodu w podanym szablonie przeanalizujmy przykład, który jest do niego dołączony. Mi wygodnie będzie to zrobić za pomocą następującego dialogu:&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;A.&lt;/b&gt; Tych funkcji jest kilka. Kodu samego nie ma wiele. Czy robi on coś konkretnego?&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;B.&lt;/b&gt; Wszystko co możemy zobaczyć na ekranie odbywa się w funkcji &lt;i&gt;draw()&lt;/i&gt;. W tym przykładzie widać wyraźnie, że rysuje ona okręgi o promieniu 30 w punkcie o współrzędnych x, y.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;A.&lt;/b&gt; Nie wydaje się to nic szczególnie ciekawego.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;B.&lt;/b&gt; Warto teraz zajrzeć do funkcji &lt;i&gt;update()&lt;/i&gt;. To tutaj znajduje się właściwe centrum sterowania aplikacji. To tutaj iteracyjnie modyfikowane są wybrane parametry elementów, które są wyświetlane na ekranie. W przypadku okręgu, o którym mowa, własnie w tej funkcji jest zaprogramowane, aby poruszał się on w linii prostej i odbijał się od krawędzi. &lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="https://lh5.googleusercontent.com/_AeFiJN9phoM/TZ4WgkeA4NI/AAAAAAAAGAs/pe5Lt3uV7SE/OpenCv-interactive_app_tutorial_1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="350" src="https://lh5.googleusercontent.com/_AeFiJN9phoM/TZ4WgkeA4NI/AAAAAAAAGAs/pe5Lt3uV7SE/OpenCv-interactive_app_tutorial_1.png" width="500" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
Domyślam się, że przedstawiony szablon nie pokazuje nic szczególnie odkrywczego ;-). Wielu zaawansowanych programistów &lt;i&gt;OpenCV&lt;/i&gt;, do których ja się raczej nie zaliczam, pewnie stosuje podobne i lepsze rozwiązania od dawna. Mam jedynie nadzieje, że okaże się on przydatny dla osób, które dopiero zaczynają przygodę z &lt;i&gt;OpenCV&lt;/i&gt; i chcą napisać swój pierwszy interaktywny program.&lt;br /&gt;
&lt;br /&gt;
Czekam oczywiście na uwagi i komentarze co można poprawić i co można zrobić lepiej.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Aktualizacja 2011.04.11&lt;/b&gt;: Opisany w tym wpisie szkielet aplikacji &lt;i&gt;OpenCV&lt;/i&gt; ma kilka niedoskonałości. Opisałem je we wpisie&amp;nbsp;&lt;i&gt;&lt;a href="http://rpetryniak.blogspot.com/2011/04/poprawiony-szkielet-aplikacji.html"&gt;Poprawiony szkielet aplikacji interaktywnej dla OpenCV&lt;/a&gt;&lt;/i&gt;. Zaproponowałem tam również jego udoskonaloną wersję. Szablon opisany w tym wpisie może być jednak z powodzeniem stosowany do&amp;nbsp;prostszych&amp;nbsp;aplikacji.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19722740-9196938830824373411?l=rpetryniak.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://rpetryniak.blogspot.com/feeds/9196938830824373411/comments/default" title="Komentarze do posta" /><link rel="replies" type="text/html" href="http://rpetryniak.blogspot.com/2011/04/obiektowy-szkielet-aplikacji.html#comment-form" title="Komentarze (2)" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/19722740/posts/default/9196938830824373411?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/19722740/posts/default/9196938830824373411?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RafalPetryniakBlog/~3/gWzz2nkwhqk/obiektowy-szkielet-aplikacji.html" title="Obiektowy szkielet aplikacji interaktywnej dla OpenCV" /><author><name>Rafał Petryniak</name><uri>https://profiles.google.com/106420849521837640393</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-ueopwOVHATs/AAAAAAAAAAI/AAAAAAAAGaw/TSrE-0eH8Zc/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://lh5.googleusercontent.com/_AeFiJN9phoM/TZ4WgkeA4NI/AAAAAAAAGAs/pe5Lt3uV7SE/s72-c/OpenCv-interactive_app_tutorial_1.png" height="72" width="72" /><thr:total>2</thr:total><feedburner:origLink>http://rpetryniak.blogspot.com/2011/04/obiektowy-szkielet-aplikacji.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0UMSHY9cSp7ImA9WhZWFUU.&quot;"><id>tag:blogger.com,1999:blog-19722740.post-4231040556386049423</id><published>2011-04-06T00:15:00.001+02:00</published><updated>2011-05-16T23:28:09.869+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-05-16T23:28:09.869+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="otwarty kod" /><category scheme="http://www.blogger.com/atom/ns#" term="systemy interaktywne" /><category scheme="http://www.blogger.com/atom/ns#" term="OpenCV" /><title>Detekcja ruchu w OpenCV - porównanie klatek</title><content type="html">&lt;table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; margin-left: 1em; text-align: right;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="https://github.com/rpetryniak/OpenCv-Interactive-Apps-And-Examples/tree/master/MotionDetection" imageanchor="1" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://riad.pk.edu.pl/%7Erpetryniak/website_resources/images/logo/github-logo1.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;&lt;a href="https://github.com/rpetryniak/OpenCv-Interactive-Apps-And-Examples/tree/master/MotionDetection"&gt;Pełny kod źródłowy&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;i&gt;OpenCV&lt;/i&gt; zostało stworzone i jest głównie używane tam, gdzie jest potrzebna zaawansowana analiza sekwencji wideo. Jest to narzędzie, które zawiera nie tylko funkcje obsługujące pobieranie obrazu z kamery, ale również funkcje, które potrafią ten obraz przetwarzać i wydobywać z niego ważne dla nas informacje. W przypadku analizy sekwencji wideo jednym z ważniejszych zadań jest detekcja miejsc, gdzie wystąpił ruch. Sama detekcja nie musi być szczególnie problematyczna, jeśli chodzi nam jedynie o proste wskazanie obszarów, na których coś się rusza. Wystarczy jedynie sprawdzić, które piksele na kolejnych klatkach obrazu zmieniają swoją wartość i podjąć decyzję na ile ta zmiana powinna być istotna, aby wykryć rzeczywisty ruch obiektu, a nie np. zaburzenia oświetlenia, bądź też ruch cienia obiektu. Oczywiście istnieje wiele problemów, które wymagają bardziej zaawansowanych algorytmów, aniżeli proste porównywanie obrazów. Możemy do nich mi.in zaliczyć rozpoznawanie i śledzenie wybranych obiektów.&lt;br /&gt;
&lt;br /&gt;
W dzisiejszym wpisie chciałem pokazać proste rozwiązanie problemu detekcji ruchu z wykorzystaniem biblioteki &lt;i&gt;OpenCV&lt;/i&gt;. Skorzystam tutaj z opisanej powyżej koncepcji sprawdzania, które punkty obrazu zmieniają swoją wartość na kolejnych obrazach w sekwencji wideo. Najłatwiej w tym celu skorzystać z operacji odejmowania obrazów, a następnie binaryzacji obrazu wynikowego w celu określenia, jaka zmiana wartości pikseli powinna zostać uznana za ruch obiektu, a jaka za brak ruchu. Najczęściej stosuje się tutaj jedną z dwoch strategii odejmowania obrazów:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;odejmowanie dwóch sąsiednich obrazów, tzn. odejmowanie od bieżącej klatki, klatki poprzedniej,&lt;/li&gt;
&lt;li&gt;odejmowanie od bieżącej klatki, pierwszej klatki, która została zarejestrowana i która jest uznawana jako tło (zakładamy oczywiście, że na pierwszej klatce nie ma obiektów, które później będą zmieniać swoje położenie).&lt;/li&gt;
&lt;/ul&gt;Oba powyższe podejścia pomimo tego, że są bardzo zbliżone do siebie dają całkiem różne rezultaty. Pierwszy sposób wskazuje jedynie, na fragmenty obiektu, które zmieniły swoją lokalizację w sekwencji ruchu, podczas gdy drugi powinien wskazać cały obszar poruszającego się obiektu.&lt;br /&gt;
&lt;br /&gt;
Implementacja opisanych metod w &lt;i&gt;OpenCV&lt;/i&gt; nie nastręcza wiele problemów. Obydwa sposoby mogą być zaimplementowane z pomocą poniższego fragmentu kodu:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint lang-cpp notranslate"&gt;//TESTED WITH OpenCV 2.2

int diffType = atoi( argv[1] );
int thresval = atoi( argv[2] );

Mat cam_frame, img_gray, img_prev, img_diff, img_bin;

bool first_frame = true;

// LOOP FOR GRABBING IMAGE FROM WEBCAM 

cap &amp;gt;&amp;gt; cam_frame;
cvtColor(cam_frame, img_gray, CV_BGR2GRAY);

if (first_frame) {
    img_prev=img_gray.clone();
    first_frame = false;
    continue;
}

absdiff(img_gray, img_prev, img_diff);
threshold(img_diff, img_bin, thresval, 255, THRESH_BINARY);
erode(img_bin,  img_bin, Mat(), Point(-1,-1), 3);
dilate(img_bin, img_bin, Mat(), Point(-1,-1), 1);

imshow(win_cam,  cam_frame);
imshow(win_gray, img_gray);
imshow(win_diff, img_bin);

if (diffType == 1) img_prev=img_gray.clone();

// END LOOP&lt;/pre&gt;&lt;br /&gt;
Analizując powyższy kod łatwo zauważyć, że jego działaniem możemy sterować za pomocą dwóch zmiennych:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;b&gt;diffType&lt;/b&gt;&lt;/span&gt; - określa, którą klatkę należy odejmować od klatki bieżącej, czy poprzednią (wartość = &lt;i&gt;1&lt;/i&gt;), czy też pierwszą (wartość = &lt;i&gt;2&lt;/i&gt;). To sprawdzanie odbywa się w ostatniej linijce powyższego kodu, gdzie jest ustawiana klatka, która będzie odejmowana.&lt;/li&gt;
&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;b&gt;thresval&lt;/b&gt;&lt;/span&gt; - zmienna ta będzie służyć do określania, co uznajemy za ruch obiektu, a co nie. Polecam ustawiać ją w przedziale od &lt;i&gt;30&lt;/i&gt; do &lt;i&gt;100&lt;/i&gt; (&lt;i&gt;60&lt;/i&gt; powinno być w miarę bezpieczną, a zarazem skuteczną wartością progu).&lt;/li&gt;
&lt;/ul&gt;Aby nie wchodzić w szczegółową analizę działania powyższego kodu, opiszę jedynie w skrócie jego najważniejsze fragmenty:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;W pierwszym przebiegu pętli zapamiętujemy jedynie pierwszą klatkę obrazu. Dzięki temu w drugiej iteracji będziemy mieli co odejmować od klatki bieżącej.&lt;/li&gt;
&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;b&gt;absdiff&lt;/b&gt;&lt;/span&gt; - bezwzględne&amp;nbsp;odjęcie&amp;nbsp;(pomijamy znak)&amp;nbsp;dwóch klatek od siebie.&lt;/li&gt;
&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;b&gt;threshold&lt;/b&gt;&lt;/span&gt; - operacja progowania wykonywana na obrazie różnicowym. Pomijamy punkty, które nieznacznie zmieniły swoją wartość.&lt;/li&gt;
&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;b&gt;erode&lt;/b&gt;&lt;/span&gt; - usunięcie drobnych elementów, oraz wygładzenie krawędzi tych większych. Skutkiem ubocznym tej operacji jest zmniejszenie rozmiaru wszystkich obiektów.&lt;/li&gt;
&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;b&gt;dilate&lt;/b&gt;&lt;/span&gt; - dylatację stosujemy po etapie erozji, aby delikatnie powiększyć obiekty, tak aby miały podobny rozmiar jak to było przed erozją. &amp;nbsp;&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;Aby dalej się nie rozpisywać na temat tego bądź co bądź krótkiego fragmentu kodu, zapraszam do obejrzenia filmiku na którym widać&amp;nbsp;obie opisywane metody&amp;nbsp;w działaniu.&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: center;"&gt;&lt;iframe allowfullscreen="" frameborder="0" height="311" src="http://www.youtube.com/embed/KREoXEy9ojY" title="YouTube video player" width="500"&gt;&lt;/iframe&gt;&lt;br /&gt;
&lt;a href="http://www.youtube.com/watch_popup?v=KREoXEy9ojY&amp;amp;vq=hd720" target="_blank"&gt;&lt;i&gt;Oglądaj film w rozdzielczości HD na pełnym ekranie.&lt;/i&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19722740-4231040556386049423?l=rpetryniak.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://rpetryniak.blogspot.com/feeds/4231040556386049423/comments/default" title="Komentarze do posta" /><link rel="replies" type="text/html" href="http://rpetryniak.blogspot.com/2011/04/detekcja-ruchu-w-opencv-porownanie.html#comment-form" title="Komentarze (0)" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/19722740/posts/default/4231040556386049423?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/19722740/posts/default/4231040556386049423?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RafalPetryniakBlog/~3/HI5Pz_hSJ2A/detekcja-ruchu-w-opencv-porownanie.html" title="Detekcja ruchu w OpenCV - porównanie klatek" /><author><name>Rafał Petryniak</name><uri>https://profiles.google.com/106420849521837640393</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-ueopwOVHATs/AAAAAAAAAAI/AAAAAAAAGaw/TSrE-0eH8Zc/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://img.youtube.com/vi/KREoXEy9ojY/default.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://rpetryniak.blogspot.com/2011/04/detekcja-ruchu-w-opencv-porownanie.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEYCRn08fSp7ImA9WhZSFkg.&quot;"><id>tag:blogger.com,1999:blog-19722740.post-6224134167960311684</id><published>2011-04-01T00:31:00.001+02:00</published><updated>2011-04-01T13:09:27.375+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-04-01T13:09:27.375+02:00</app:edited><title>Obsługa parametrów wywołania programu w C++</title><content type="html">Pisząc programy konsolowe niejednokrotnie spotykamy się problemem przekazywania parametrów startowych.&amp;nbsp;Najczęstszym&amp;nbsp;rozwiązaniem jest ich wpisywanie zaraz po nazwie programu, dzięki czemu będą one później dostępne w tablicy &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;b&gt;argv&lt;/b&gt;&lt;/span&gt; funkcji&amp;nbsp;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;b&gt;main&lt;/b&gt;&lt;/span&gt;. Innym&amp;nbsp;rozwiązaniem, rzadziej stosowanym jest ich zapisywanie do pliku tekstowego, np. XML i&amp;nbsp;dalsze&amp;nbsp;jego parsowanie zaraz po starcie programu. To drugie rozwiązanie zalecane jest raczej w przypadku&amp;nbsp;naprawdę&amp;nbsp;złożonych parametrów wywołania. W większości&amp;nbsp;przypadków w&amp;nbsp;zupełności&amp;nbsp;wystarcza proste przekazywanie parametrów po nazwie programu w trakcie jego wywołania.&lt;br /&gt;
&lt;br /&gt;
Podejście&amp;nbsp;klasyczne o przykładowym zapisie:&lt;br /&gt;
&lt;pre class="prettyprint lang-cpp notranslate"&gt;int zmienna1 = atoi (argv[1]);
int zmienna2 = atoi (argv[3]);&lt;/pre&gt;może być kłopotliwe w stosowaniu, ponieważ wymaga dokładnego pamiętania kolejności poszczególnych parametrów. Znacznie lepszym rozwiązaniem są &lt;u&gt;parametry nazwane&lt;/u&gt;, co do których ten wymóg nie jest już konieczny. Parametry tego typu znane są na pewno każdemu, kto jakiś czas pracował w konsoli tekstowej i potrzebował zmodyfikować domyślne parametry działania programu lub podać własne.&lt;br /&gt;
&lt;br /&gt;
Obecnie jest kilka mechanizmów obsługi tego typu parametrów w języku C++. Niestety nie są one wbudowane do biblioteki standardowej i wymagają stosowania zewnętrznych&amp;nbsp;bibliotek, które mają nie tylko mocne, ale&amp;nbsp;również&amp;nbsp;słabe&amp;nbsp;strony. Oto niektóre z nich:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Boost.Program_options&lt;/span&gt; - jeśli ktoś nie miał do tej pory potrzeby korzystania z bibliotek &lt;i&gt;Boost&lt;/i&gt; to nie wydaje się dobrym pomysłem włączanie ich do projektu tylko ze względu na obsługę parametrów wejściowych. Bardziej szczegółowy opis biblioteki można znaleźć &lt;a href="http://www.boost.org/doc/html/program_options.html"&gt;tutaj&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;GNU&amp;nbsp;getopt&lt;/span&gt; - użycie tego narzędzia w praktyce wymaga od użytkownika napisania kodu zawierającego instrukcję pętli &lt;i&gt;while&lt;/i&gt; i przełącznik &lt;i&gt;switch&lt;/i&gt;, przez co implementacja programu niepotrzebnie się wydłuża i może tracić czytelność (szczególnie w przypadku krótkich programów). Przykładowy program można zobaczyć w &lt;a href="http://www.gnu.org/s/libc/manual/html_node/Example-of-Getopt.html"&gt;oficjalnej dokumentacji&lt;/a&gt;.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Do innych rozwiązań tego typu można zaliczyć:&amp;nbsp;&lt;a href="http://code.google.com/p/google-gflags/"&gt;bibliotekę&amp;nbsp;google-gflags&lt;/a&gt;, &lt;a href="http://opensource.dshevchenko.biz/clpp"&gt;bibliotekę&amp;nbsp;CLPP&lt;/a&gt;,&amp;nbsp;&lt;a href="http://artis.imag.fr/~Xavier.Decoret/resources/argstream/"&gt;argstream&lt;/a&gt;,&amp;nbsp;&lt;a href="http://clp.sourceforge.net/"&gt;clp&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;Każde z powyższych rozwiązań, nawet jeśli w praktyce działa bardzo dobrze, wymaga korzystania z dodatkowych bibliotek, co do których należy mieć pewność, że zostały poprawnie zainstalowane w systemie. Dodatkowo w przypadku, niedużych programów, nie wydaje się sensowne korzystanie z bibliotek, które swoim rozmiarem znacznie przewyższają kod implementowanego algorytmu. Ja osobiście nie przekonałem się do żadnej z powyższych bibliotek, dlatego postanowiłem sam zaprogramować obsługę parametrów wywołania programu.&lt;br /&gt;
&lt;br /&gt;
Poniższe rozwiązanie przygotowałem na podstawie przykładu ze strony:&amp;nbsp;&lt;a href="http://stackoverflow.com/questions/865668/parse-command-line-arguments/868894#868894"&gt;http://stackoverflow.com/questions/865668/parse-command-line-arguments/868894#868894&lt;/a&gt;. Przykład ten niestety nie działał do końca poprawnie i ostateczne rozwiązanie udało mi sie przygotowac analizując kod biblioteki &lt;i&gt;&lt;a href="http://rpetryniak.blogspot.com/2008/07/cimg_19.html"&gt;CImg&lt;/a&gt;&lt;/i&gt;, którą używam do przetwarzania obrazu, a która to miała zaimplementowany podobny mechanizm. Poniższego kodu nie będe szczegółowo opisywał. Mam nadzieje, że jest on wystarczająco czytelny :-).&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Funkcja parsująca parametry wywołania programu w C++:&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint lang-cpp notranslate"&gt;inline const char*  getCmdOption(const char * name, const char * defaut, const int argc, const char *const * argv)
{
  const char *res = 0;
  
  if (argc &amp;gt; 0) {
    int k = 0;
    while (k &amp;lt; argc &amp;amp;&amp;amp; strcmp(argv[k],name)) ++k;
    res = (k++==argc?defaut:(k==argc?argv[--k]:argv[k]));
  } else res = defaut;
  
  return res;
}&lt;/pre&gt;&lt;br /&gt;
&lt;b&gt;Przykładowe użycie funkcji&amp;nbsp;&lt;i&gt;getCmdOption&lt;/i&gt;:&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Funkcja&amp;nbsp;&lt;i&gt;getCmdOption&lt;/i&gt;&amp;nbsp;już okazała mi się pomocna w kilku programach z zakresu przetwarzania obrazu. Poniżej fragment programu do wczytywania danych binarnych, ze szczególnym uwzględnieniem obsługi parametrów wejściowych:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint lang-cpp notranslate"&gt;if (argc == 1) {
  printf("Usage: %s -f filename.raw -dx [value] -dy [value] -dz [value]\n", argv[0]);
  exit(0);
}

const char * filename  = getCmdOption("-f",    (char*)0, argc, argv );
const char * _dx       = getCmdOption("-dx",   (char*)0, argc, argv );
const char * _dy       = getCmdOption("-dy",   (char*)0, argc, argv );
const char * _dz       = getCmdOption("-dz",   (char*)0, argc, argv );

if ((char*)0 == filename) { 
  printf("Please specify input data file name (-f)\n"); 
  exit(0);
}
if ((char*)0 == _dx || (char*)0 == _dx || (char*)0 == _dx) { 
  printf("Please specify input data dimension sizes (-dx, -dy, -dz)\n"); 
  exit(0);
}

int dx = atoi( _dx );
int dy = atoi( _dy );
int dz = atoi( _dz );&lt;/pre&gt;&lt;br /&gt;
To co było dla mnie najważniejsze i co mam nadzieje udało mi się uzyskać, to duża czytelność kodu. Mam nadzieje, że proponowana funkcja&amp;nbsp;&lt;i&gt;getCmdOption&lt;/i&gt;, okaże się również przydatna dla innych.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19722740-6224134167960311684?l=rpetryniak.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://rpetryniak.blogspot.com/feeds/6224134167960311684/comments/default" title="Komentarze do posta" /><link rel="replies" type="text/html" href="http://rpetryniak.blogspot.com/2011/04/obsuga-parametrow-wywoania-programu-w-c.html#comment-form" title="Komentarze (0)" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/19722740/posts/default/6224134167960311684?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/19722740/posts/default/6224134167960311684?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RafalPetryniakBlog/~3/t7iG1IfSngc/obsuga-parametrow-wywoania-programu-w-c.html" title="Obsługa parametrów wywołania programu w C++" /><author><name>Rafał Petryniak</name><uri>https://profiles.google.com/106420849521837640393</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-ueopwOVHATs/AAAAAAAAAAI/AAAAAAAAGaw/TSrE-0eH8Zc/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://rpetryniak.blogspot.com/2011/04/obsuga-parametrow-wywoania-programu-w-c.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEQMSHY6eSp7ImA9WhZSFkg.&quot;"><id>tag:blogger.com,1999:blog-19722740.post-5830296881790230180</id><published>2011-03-24T21:05:00.000+01:00</published><updated>2011-04-01T13:13:09.811+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-04-01T13:13:09.811+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="cmake" /><category scheme="http://www.blogger.com/atom/ns#" term="systemy interaktywne" /><category scheme="http://www.blogger.com/atom/ns#" term="OpenCV" /><title>Wygodna konfiguracja procesu budowania programów OpenCV w CMake</title><content type="html">O sposobach kompilacji programów &lt;i&gt;OpenCV&lt;/i&gt; w &lt;i&gt;Linuksie&lt;/i&gt; pisałem ostatnio we wpisie&amp;nbsp;&lt;i&gt;&lt;a href="http://rpetryniak.blogspot.com/2011/03/opencv-instalacja-i-pierwszy-przykad-w.html"&gt;OpenCV - instalacja i pierwszy przykład w Ubuntu&lt;/a&gt;&lt;/i&gt;. Pokazalem tam również przykladowy plik konfiguracyjny dla &lt;i&gt;CMake&lt;/i&gt;: &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;CMakeLists.txt&lt;/span&gt;. Na pierwszy rzut oka wydaje się on w porządku, jednakże jeśli zacznie nam przybywać nowych programów, wówczas kopiowanie tych dwóch linijek rozpoczynających się od &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;ADD_EXECUTABLE&lt;/span&gt; i&amp;nbsp;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;TARGET_LINK_LIBRARIES&lt;/span&gt; może być irytujące. Można oczywiście sobie z tym poradzić i przekonać &lt;i&gt;CMake&lt;/i&gt; d bardziej zautomatyzowanej pracy - przykład poniżej:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint lang-cpp notranslate"&gt;PROJECT(NazwaProjektu)

cmake_minimum_required(VERSION 2.8)

FIND_PACKAGE( OpenCV REQUIRED )

SET(SOURCES
  aplikacja1
  aplikacja2
  aplikacja3
  aplikacja4 
)

FOREACH(source ${SOURCES})
  ADD_EXECUTABLE(${source} ${source}.cpp)
  TARGET_LINK_LIBRARIES(${source} ${OpenCV_LIBS})
ENDFOREACH(source)&lt;/pre&gt;&lt;br /&gt;
Jak łatwo zauważyć, dodawanie nowego programu do kompilacji nie wymaga wiele wysiłku. Wystarczy dodać nazwę pliku z kodem źródłowym w sekcji &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;SOURCES&lt;/span&gt; i gotowe.&lt;br /&gt;
&lt;br /&gt;
Życzę przyjemnej kompilacji programów &lt;i&gt;OpenCV&lt;/i&gt; :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19722740-5830296881790230180?l=rpetryniak.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://rpetryniak.blogspot.com/feeds/5830296881790230180/comments/default" title="Komentarze do posta" /><link rel="replies" type="text/html" href="http://rpetryniak.blogspot.com/2011/03/wygodna-konfiguracja-procesu-budowania.html#comment-form" title="Komentarze (0)" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/19722740/posts/default/5830296881790230180?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/19722740/posts/default/5830296881790230180?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RafalPetryniakBlog/~3/EuV8NCNqyS0/wygodna-konfiguracja-procesu-budowania.html" title="Wygodna konfiguracja procesu budowania programów OpenCV w CMake" /><author><name>Rafał Petryniak</name><uri>https://profiles.google.com/106420849521837640393</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-ueopwOVHATs/AAAAAAAAAAI/AAAAAAAAGaw/TSrE-0eH8Zc/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://rpetryniak.blogspot.com/2011/03/wygodna-konfiguracja-procesu-budowania.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0MFQH85eip7ImA9WhZWFUU.&quot;"><id>tag:blogger.com,1999:blog-19722740.post-8024139252020910812</id><published>2011-03-22T22:57:00.002+01:00</published><updated>2011-05-16T23:30:11.122+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-05-16T23:30:11.122+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="otwarty kod" /><category scheme="http://www.blogger.com/atom/ns#" term="systemy interaktywne" /><category scheme="http://www.blogger.com/atom/ns#" term="OpenCV" /><title>Dostęp do składowych piksela w OpenCV 2.2</title><content type="html">&lt;table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; margin-left: 1em; text-align: right;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="https://github.com/rpetryniak/OpenCv-Interactive-Apps-And-Examples/tree/master/AssignPixel" imageanchor="1" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://riad.pk.edu.pl/%7Erpetryniak/website_resources/images/logo/github-logo1.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;&lt;a href="https://github.com/rpetryniak/OpenCv-Interactive-Apps-And-Examples/tree/master/AssignPixel"&gt;Pełny kod źródłowy&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;Wraz ze zmianą wersji biblioteki &lt;i&gt;OpenCV&lt;/i&gt; z &lt;b&gt;&lt;i&gt;2.1&lt;/i&gt;&lt;/b&gt; na &lt;b&gt;&lt;i&gt;2.2&lt;/i&gt;&lt;/b&gt; doszło do wielu zmian nie tylko w zakresie organizacji modułów, ale również w zakresie sposobu programowania. Dokładnie nie śledziłem jakie&amp;nbsp;zaszły&amp;nbsp;zmiany, więc nie będę ich dokładnie opisywał, jednak zauważyłem, że został położony większy nacisk na programowanie obiektowe. Widoczne jest to szczególnie w strukturach przechowujących obraz. Od zawsze do tego celu korzystało się ze struktury&amp;nbsp;&lt;i&gt;&lt;b&gt;IplImage&lt;/b&gt;&lt;/i&gt;, natomiast teraz zalecane jest używanie klasy &lt;i&gt;&lt;b&gt;cv::Mat&lt;/b&gt;&lt;/i&gt;, która reprezentuje wielowymiarowe macierze danych. Aby szczegółowo zapoznać się z konstrukcją tej klasy najlepiej zajrzeć do oficjalnej dokumentacji pod hasło&amp;nbsp;&lt;a href="http://opencv.jp/opencv-2.2_org/cpp/core_basic_structures.html#mat"&gt;&lt;i&gt;Basic Structures → Mat&lt;/i&gt;&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Pierwszym problemem podczas przejścia ze struktury&amp;nbsp;&lt;i&gt;IplImage&lt;/i&gt; do używania klasy &lt;i&gt;Mat&lt;/i&gt; będzie zapewne to, jak odczytać i zmodyfikować zawartość poszczególnych składowych piksela. Do tej pory było kilka sposobów, żeby sobie z tym poradzić (polecam wpis na oficjalnym &lt;i&gt;Wiki&lt;/i&gt; pod hasłem: &lt;a href="http://opencv.willowgarage.com/wiki/faq#Howtoaccessimagepixels"&gt;&lt;i&gt;How to access image pixels&lt;/i&gt;&lt;/a&gt;). Teraz podobnie, mamy kilka możliwości, aby dostać się do piksela, jednak dokumentacja opisuje to bardzo pobieżnie. W rozdziale&amp;nbsp;&lt;i&gt;&lt;a href="http://opencv.jp/opencv-2.2_org/cpp/fast_element_access.html"&gt;Introduction →&amp;nbsp;Fast Element Access&lt;/a&gt;&lt;/i&gt; zostały pokazane 3 różne sposoby operowania na pikselach obrazu, jednak dla mnie wydają się one kłopotliwe w użyciu. To właśnie było powodem przygotowania niniejszego poradnika, w którym chciałem przedstawić własne i znalezione w Internecie wygodne sposoby dostępu do składowych piksela.&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: x-large;"&gt;Obrazy w skali szarości&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Na początek, aby nabrać wprawy najlepiej zrobić proste testy z wykorzystaniem obrazów 1-kanałowych. W tym celu obrazy pozyskane z kamery można przekonwertować na obraz szary i na nim wykonywać dalsze operacje.&lt;br /&gt;
&lt;br /&gt;
Poniżej został pokazany fragment kodu, który zawiera 3 sposoby dostępu do piksela, począwszy od tego najbardziej tradycyjnego, gdzie operujemy bezpośrednio na tablicy z danymi (&lt;i&gt;metoda 1&lt;/i&gt;), poprzez użycie funkcji &lt;b&gt;&lt;i&gt;at()&lt;/i&gt;&lt;/b&gt;, której przekazujemy współrzędne interesującego nas punktu (&lt;i&gt;metoda 2&lt;/i&gt;), a skończywszy na zastosowaniu wskaźnika do każdego analizowanego wiersza obrazu (&lt;i&gt;metoda 3&lt;/i&gt;). Z tych 3 metod podejście obiektowe jest reprezentowane przez sposób 2, podczas gdy pozostałe 2 przypadki działają bardziej tradycyjnie.&lt;br /&gt;
&lt;br /&gt;
Aby skupić się na tym co istotne, poniższy kod zawiera jedynie najważniejszą część programu, z deklaracją używanych struktur reprezentujących obraz, oraz środkiem pętli przetwarzającej obraz z kamery. Aby uruchomić ten program można skorzystać z szablonu, który podałem w poprzednim wpisie&amp;nbsp;&lt;i&gt;&lt;a href="http://rpetryniak.blogspot.com/2011/03/opencv-instalacja-i-pierwszy-przykad-w.html"&gt;OpenCV - instalacja i pierwszy przykład w Ubuntu&lt;/a&gt;&lt;/i&gt; w sekcji&amp;nbsp;&lt;i&gt;Ten sam przykład po nowemu&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint lang-cpp notranslate"&gt;Mat cam_frame, img_gray_v1, img_gray_v2, img_gray_v3;

// LOOP FOR GRABBING IMAGE FROM WEBCAM 

cap &amp;gt;&amp;gt; cam_frame;

// Method 1: Old style method operating on data array
cvtColor(cam_frame, img_gray_v1, CV_BGR2GRAY);

for(int i = 0; i &amp;lt; img_gray_v1.rows; i++)
  for(int j = 0; j &amp;lt; img_gray_v1.cols; j++) {
    img_gray_v1.data[img_gray_v1.step*i + j] = 255 - img_gray_v1.data[img_gray_v1.step*i + j];
  }

// Method 2: Assign pixel using .at() function
cvtColor(cam_frame, img_gray_v2, CV_BGR2GRAY);

for(int i = 0; i &amp;lt; img_gray_v2.rows; i++)
  for(int j = 0; j &amp;lt; img_gray_v2.cols; j++)
    img_gray_v2.at&lt;uchar&gt;(i,j) = 255 - img_gray_v2.at&lt;uchar&gt;(i,j);      

// Method2: Use plain C operator []. More efficient than method 2 
//    if you need to process a whole row of a 2d array
cvtColor(cam_frame, img_gray_v3, CV_BGR2GRAY);

for(int i = 0; i &amp;lt; img_gray_v3.rows; i++)
{
  uchar* img_gray_v3_i = img_gray_v3.ptr&lt;uchar&gt;(i);
  for(int j = 0; j &amp;lt; img_gray_v3.cols; j++)
    img_gray_v3_i[j] = 255 - img_gray_v3_i[j];
}

// END LOOP&lt;/uchar&gt;&lt;/uchar&gt;&lt;/uchar&gt;&lt;/pre&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: x-large;"&gt;Obrazy wielokanałowe&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Większy problem aniżeli obrazy 1-kanałowe sprawiają obrazy kolorowe, domyślnie uzyskiwane z tradycyjnych kamer cyfrowych. Należy tutaj pamiętać nie tylko o współrzędnych punktu, który jest analizowany, ale również o jego składowej koloru. na szczęście jest na to kilka sposobów, które można prześledzić poniżej.&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;Podejście tradycyjne&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Podobnie jak w przypadku obrazów szarych, dla obrazów wielokanałowych można również skorzystać z podejścia znanego z obróbki struktur &lt;i&gt;IplImage&lt;/i&gt;&amp;nbsp;i przeliczać wskaźnik do elementu, który nas interesuje. Przykład poniżej:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint lang-cpp notranslate"&gt;Mat frame, result;

// LOOP FOR GRABBING IMAGE FROM WEBCAM 

cap &amp;gt;&amp;gt; frame;

result = frame.clone();

// invert the image
for(i=0; i &amp;lt; frame.rows; i++) 
  for(j=0; j &amp;lt; frame.cols; j++) 
    for(k=0; k &amp;lt; channels; k++) {

      uchar* temp_ptr = &amp;amp;((uchar*)(result.data + result.step*i))[j*3];
      temp_ptr[0] = 255 - temp_ptr[0];
      temp_ptr[1] = 255 - temp_ptr[1];
      temp_ptr[2] = 255 - temp_ptr[2];    
    }

// END LOOP&lt;/pre&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;Sposoby opisane w oficjalnej dokumentacji&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Tak jak wspomniałem na początku tego wpisu, w oficjalnej dokumentacji we wpisie&amp;nbsp;&lt;i&gt;&lt;a href="http://opencv.jp/opencv-2.2_org/cpp/fast_element_access.html"&gt;Introduction →&amp;nbsp;Fast Element Access&lt;/a&gt;&lt;/i&gt;&amp;nbsp;pokazano 3 sposoby na to jak dostać się do składowych piksela. Dla mnie osobiście dziwne wydaje się rozbijanie obrazu wielokanałowego na obrazy zawierające jeden kanał i po wykonaniu obliczeń ponowne ich scalanie. Nie dość, że wydłuża to zapis algorytmu obróbki obrazu, to mam wrażenie, że powoduje dodatkowy narzut obliczeniowy. Kod z drobnymi poprawkami względem wersji oryginalnej znajduje się poniżej:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint lang-cpp notranslate"&gt;Mat img_frame, img_resultA, img_resultB, img_resultC;
vector&lt;mat&gt; planesA,planesB,planesC;

// LOOP FOR GRABBING IMAGE FROM WEBCAM 

cap &amp;gt;&amp;gt; img_frame;
    
// Method 1. process Y plane using an iterator

split(img_frame, planesA); // split the image into separate color planes

MatIterator_&lt;uchar&gt; 
  it1     = planesA[0].begin&lt;uchar&gt;(),
  it1_end = planesA[0].end&lt;uchar&gt;(),
  it2     = planesA[1].begin&lt;uchar&gt;(),
  it3     = planesA[2].begin&lt;uchar&gt;();

for(; it1 != it1_end; ++it1,++it2,++it3 )
{
  *it1 = 255 - *it1;
  *it2 = 255 - *it2;
  *it3 = 255 - *it3;
}

merge(planesA, img_resultA);

// Method 2. process the first chroma plane using pre-stored row pointer.

split(img_frame, planesB);

for( int y = 0; y &amp;lt; img_frame.rows; y++ )
{
  uchar* Uptr1 = planesB[0].ptr&lt;uchar&gt;(y);
  uchar* Uptr2 = planesB[1].ptr&lt;uchar&gt;(y);
  uchar* Uptr3 = planesB[2].ptr&lt;uchar&gt;(y);
  
  for( int x = 0; x &amp;lt; img_frame.cols; x++ )
  {
    Uptr1[x] = 255 - Uptr1[x];
    Uptr2[x] = 255 - Uptr2[x];
    Uptr3[x] = 255 - Uptr3[x];
  }
}

merge(planesB, img_resultB);

// Method 3. process the second chroma plane using
//           individual element access operations

split(img_frame, planesC);

for( int y = 0; y &amp;lt; img_frame.rows; y++ )
{
  for( int x = 0; x &amp;lt; img_frame.cols; x++ )
  {
    uchar&amp;amp; Vxy1 = planesC[0].at&lt;uchar&gt;(y, x);
    uchar&amp;amp; Vxy2 = planesC[1].at&lt;uchar&gt;(y, x);
    uchar&amp;amp; Vxy3 = planesC[2].at&lt;uchar&gt;(y, x);
    
    Vxy1 = 255 - Vxy1;
    Vxy2 = 255 - Vxy2;
    Vxy3 = 255 - Vxy3;        
  }
}

merge(planesC, img_resultC); 

// END LOOP&lt;/uchar&gt;&lt;/uchar&gt;&lt;/uchar&gt;&lt;/uchar&gt;&lt;/uchar&gt;&lt;/uchar&gt;&lt;/uchar&gt;&lt;/uchar&gt;&lt;/uchar&gt;&lt;/uchar&gt;&lt;/uchar&gt;&lt;/mat&gt;&lt;/pre&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;Ostatnia deska ratunku&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Powyżej opisane sposoby dla obrazów wielokanałowych nie wydają się nazbyt wygodne i raczej zniechęcają, a nie zachęcają do stosowania klasy &lt;i&gt;Mat&lt;/i&gt;. Na szczęście światełkiem w tunelu jest klasa pochodna po &lt;i&gt;cv::Mat&lt;/i&gt; o niemal identycznej nazwie:&amp;nbsp;&lt;b&gt;&lt;i&gt;cv::Mat_&lt;/i&gt;&lt;/b&gt;. Klasa ta ma opracowane operatory dostępu do składowych piksela poprzez zastosowanie konstrukcji &lt;b&gt;( x , y )&lt;/b&gt;. Możemy w ten sposób uzyskać wskaźnik do konkretnego punktu obrazu, i dalej stosując zapis tablicowy &lt;b&gt;[]&lt;/b&gt; możemy dostać się do konkretnej wartości danego kanału.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Przykład 1&lt;/b&gt;: &lt;u&gt;Operowanie na oryginalnym obrazie:&lt;/u&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint lang-cpp notranslate"&gt;Mat frame;

// LOOP FOR GRABBING IMAGE FROM WEBCAM 

cap &amp;gt;&amp;gt; frame;

Mat_&lt;vec3b&gt;&amp;amp; frame_ = (Mat_&lt;vec3b&gt;&amp;amp;)frame;

for(int i = 0; i &amp;lt; frame_.rows; i++)
  for(int j = 0; j &amp;lt; frame_.cols; j++)
    for(int k = 0; k &amp;lt; 3; k++)
      frame_(i,j)[k] = 255 - frame_(i,j)[k];

// END LOOP&lt;/vec3b&gt;&lt;/vec3b&gt;&lt;/pre&gt;&lt;br /&gt;
&lt;b&gt;Przykład 2&lt;/b&gt;:&amp;nbsp;&lt;u&gt;Operowanie na obrazie pomocniczym:&lt;/u&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint lang-cpp notranslate"&gt;Mat frame;
Mat_&lt;vec3b&gt; rgb;

// LOOP FOR GRABBING IMAGE FROM WEBCAM 

cap &amp;gt;&amp;gt; frame;

cvtColor(frame, rgb, CV_BGR2RGB);

for(int i = 0; i &amp;lt; rgb.rows; i++)
  for(int j = 0; j &amp;lt; rgb.cols; j++)
    for(int k = 0; k &amp;lt; 3; k++)
      rgb(i,j)[k] = 255 - rgb(i,j)[k];

// END LOOP&lt;/vec3b&gt;&lt;/pre&gt;&lt;br /&gt;
Podsumowując zebrane w tym poradniku sposoby dostępu do składowych piksela, najwygodniejsze wydaje się użycie operatora &lt;b&gt;&lt;i&gt;at()&lt;/i&gt;&lt;/b&gt; dla obrazów jednokanałowych, &amp;nbsp;natomiast dla obrazów wielokanałowych najprostszy i najbardziej czytelny zapis daje klasa &lt;b&gt;&lt;i&gt;cv::Mat_&lt;/i&gt;&lt;/b&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19722740-8024139252020910812?l=rpetryniak.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://rpetryniak.blogspot.com/feeds/8024139252020910812/comments/default" title="Komentarze do posta" /><link rel="replies" type="text/html" href="http://rpetryniak.blogspot.com/2011/03/dostep-do-skadowych-piksela-w-opencv-22.html#comment-form" title="Komentarze (2)" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/19722740/posts/default/8024139252020910812?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/19722740/posts/default/8024139252020910812?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RafalPetryniakBlog/~3/VDE0JGzKEm0/dostep-do-skadowych-piksela-w-opencv-22.html" title="Dostęp do składowych piksela w OpenCV 2.2" /><author><name>Rafał Petryniak</name><uri>https://profiles.google.com/106420849521837640393</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-ueopwOVHATs/AAAAAAAAAAI/AAAAAAAAGaw/TSrE-0eH8Zc/s512-c/photo.jpg" /></author><thr:total>2</thr:total><feedburner:origLink>http://rpetryniak.blogspot.com/2011/03/dostep-do-skadowych-piksela-w-opencv-22.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUMHQno6eip7ImA9WhZTFU8.&quot;"><id>tag:blogger.com,1999:blog-19722740.post-7314276032471816532</id><published>2011-03-19T00:01:00.001+01:00</published><updated>2011-03-19T09:30:33.412+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-03-19T09:30:33.412+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="systemy interaktywne" /><category scheme="http://www.blogger.com/atom/ns#" term="OpenCV" /><title>OpenCV - instalacja i pierwszy przykład w Ubuntu</title><content type="html">Już od dłuższego czasu przymierzałem się, aby więcej czasu poświęcić systemom interaktywnym, a w szczególności problematyce analizy ruchu. Zagadnieniami wizualizacji i przetwarzania obrazów medycznych oczywiście nie przestaje się dalej zajmować, jednakże opisywanie tej tematyki na blogu nie dość, że było i jest bardzo wymagające czasowo, to niestety interesuje tylko bardzo małą grupę osób. Natomiast analiza ruchu ma wiele różnych zastosowań - nie tylko tych naukowych, ale również rozrywkowych. Podobnie z punktu widzenia nauki przetwarzania informacji obrazowej, dla wielu młodych osób ciekawsze wydaje się analizowanie obrazu&amp;nbsp;z kamerki&amp;nbsp;na żywo, zamiast analizy statycznych obrazów medycznych.&lt;br /&gt;
&lt;br /&gt;
Tym wpisem rozpoczynam serię poradników dotyczących właśnie analizy ruchu. Głównym narzędziem (biblioteką) jak będzie używana będzie &lt;i&gt;OpenCV&lt;/i&gt;, o którym &lt;a href="http://rpetryniak.blogspot.com/2008/08/opencv_01.html"&gt;pisałem ponad 2 lata temu na tym blogu&lt;/a&gt;. Dzisiaj chciałbym opisać proces instalacji tej biblioteki w &lt;i&gt;Ubuntu&lt;/i&gt; i pokazać prosty przykład z użyciem kamerki internetowej.&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;Instalacja z repozytorium&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Aby zainstalować &lt;i&gt;OpenCV&lt;/i&gt; z repozytorium wpisujemy następujące polecenie w okienku terminala:&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;sudo apt-get install libcv-dev libcvaux-dev libhighgui-dev&lt;/pre&gt;&lt;br /&gt;
Patrząc na tą komendę można zauważyć, że instalowane są tylko pakiety programistyczne. A co z bibliotekami? Zainstalują się one oczywiście same jako zależności wyżej wymienionych pakietów. Takie podejście jest oczywiście bardziej uniwersalne w przypadku instalacji &lt;i&gt;OpenCV&lt;/i&gt;, ponieważ biblioteki te mają dodaną końcówkę &lt;b&gt;&lt;i&gt;2.1&lt;/i&gt;&lt;/b&gt; (np.&amp;nbsp;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;libcv2.1&lt;/span&gt;), a tak nie będzie zawsze. Dla przykładu na &lt;a href="http://opencv.willowgarage.com/wiki/"&gt;stronie projektu&lt;/a&gt; jest już dostępna wersja &lt;b&gt;&lt;i&gt;2.2&lt;/i&gt;&lt;/b&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;Instalacja ze źródeł&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Tak jak wspomniałem powyżej, wersja, która znajduje się w repozytorium nie jest najświeższa i osobom, którym szczególnie zależy, aby pracować na ostatniej wersji tej biblioteki polecam samodzielną kompilację ze źródeł. Nie jest ona skomplikowana, dlatego również zostanie opisana w tym poradniku.&lt;br /&gt;
&lt;br /&gt;
Najnowszą stabilną wersję źródeł &lt;i&gt;OpenCV&lt;/i&gt; można pobrać z portalu &lt;i&gt;SourceForge&lt;/i&gt;, a dokładnie ze strony:&amp;nbsp;&lt;a href="http://sourceforge.net/projects/opencvlibrary/files/opencv-unix/"&gt;http://sourceforge.net/projects/opencvlibrary/files/opencv-unix/&lt;/a&gt;. Można pobrać ją również bezpośrednio z repozytorium, aby mieć dostęp do aktualnie wprowadzanych funkcji. W tym celu wystarczy wpisać w konsoli następujące polecenie:&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;svn co https://code.ros.org/svn/opencv/trunk&lt;/pre&gt;&lt;br /&gt;
Ja osobiście polecam wersję stabilną. Obecnie jest to wersja &lt;b&gt;&lt;i&gt;2.2&lt;/i&gt;&lt;/b&gt;.&lt;br /&gt;
&lt;br /&gt;
Teraz kiedy mamy pobrane już źródła biblioteki &lt;i&gt;OpenCV&lt;/i&gt;, możemy przystąpić do jej kompilacji. Wykonujemy w tym celu następujące kroki:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Utworzenie katalogu &lt;i&gt;build&lt;/i&gt; i uruchomienie w nim graficznej nakładki na &lt;i&gt;CMake&lt;/i&gt;:&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;mkdir build
cd build
cmake-gui ../&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;Przy pierwszej kompilacji najlepiej nie ustawiać zbyt wiele opcji, aby mieć pewność że podstawowa wersja się skompiluje. Ja ustawiłem tylko typ kompilacji na „&lt;i&gt;Release&lt;/i&gt;”&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;CMAKE_BUILD_TYPE &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Release&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;Uruchomienie kompilacji. Jeśli mamy wiecej niż jeden rdzeń warto z tego skorzystać stosując przełącznik &lt;b&gt;&lt;i&gt;j&lt;/i&gt;&lt;/b&gt;:&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;make -j2&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;Jeśli wszystko dobrze się skompiluje można wówczas uruchomić kolejne przebiegi kompilacji z włączonymi następującymi opcjami:&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;BUILD_EXAMPLES                   ON
BUILD_NEW_PYTHON_SUPPORT         ON
OPENCV_BUILD_3RDPARTY_LIBS       ON&lt;/pre&gt;Oczywiście tych opcji jest dużo więcej, dlatego polecam samodzielne testowanie pozostałych, chociaż te o których napisałem powinny w zupełności wystarczyć.&lt;br /&gt;
&lt;/li&gt;
&lt;/ul&gt;Jeśli pojawiły się jakieś niespodziewane błędy podczas kompilacji polecam zajrzeć na stronę:&lt;br /&gt;
&lt;a href="http://opencv.willowgarage.com/wiki/InstallGuide"&gt;http://opencv.willowgarage.com/wiki/InstallGuide&lt;/a&gt;&amp;nbsp;w celu znalezienia rozwiązania.&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;Pierwsze testy&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Na początek warto&amp;nbsp;przetestować&amp;nbsp;przykłady&amp;nbsp;załączone&amp;nbsp;w katalogu s&lt;i&gt;amples&lt;/i&gt;. Po kompilacji odpowiadające im wersje binarne powinny znaleźć się w katalogu: &lt;i&gt;build/bin/&lt;/i&gt;. Ja sprawdziłem wszystkie i od razu mogę podpowiedzieć, że z kamerką działają te z nich:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;adaptiveskindetector&lt;/li&gt;
&lt;li&gt;bgfg_codebook&lt;/li&gt;
&lt;li&gt;bgfg_segm&lt;/li&gt;
&lt;li&gt;camshiftdemo&lt;/li&gt;
&lt;li&gt;fback&lt;/li&gt;
&lt;li&gt;fback_c&lt;/li&gt;
&lt;li&gt;laplace&lt;/li&gt;
&lt;li&gt;lkdemo&lt;/li&gt;
&lt;li&gt;motempl&lt;/li&gt;
&lt;li&gt;segment_objects&lt;/li&gt;
&lt;/ul&gt;Pomimo tego, że nie są one szczególnie złożone, na początek warto zacząć od jeszcze&amp;nbsp;prostszych&amp;nbsp;przykładów.&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;Wyświetlanie obrazu z kamery&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Jednym z pierwszych przykładów, które warto przeanalizować i uruchomić w &lt;i&gt;OpenCV&lt;/i&gt; jest pobieranie obrazu z kamery i wyświetlenie go na ekranie monitora. Nie jest to oczywiście trudne, ale wymaga znajomości kilku elementarnych funkcji takich jak:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;cvCaptureFromCAM&lt;/span&gt; - inicjalizacja kamery,&lt;/li&gt;
&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;cvQueryFrame&lt;/span&gt; - pobranie pojedynczej klatki obrazu,&lt;/li&gt;
&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;cvShowImage&lt;/span&gt; - wyświetlenie obrazka we wskazanym oknie.&lt;/li&gt;
&lt;/ul&gt;Cały przykład wygląda następująco:&lt;br /&gt;
&lt;pre class="prettyprint lang-cpp notranslate"&gt;#include "opencv/highgui.h"

int main() 
{
  CvCapture *cam = cvCaptureFromCAM(-1);
  
  const char *window = "Example 1";
  cvNamedWindow(window, CV_WINDOW_AUTOSIZE);
  
  while (cvWaitKey(4) == -1) {
    IplImage *frame = cvQueryFrame(cam);
    cvShowImage(window, frame);
  }
  
  cvDestroyAllWindows();
  cvReleaseCapture(&amp;amp;cam);
  
  return 0;
}&lt;/pre&gt;&lt;br /&gt;
Aby go skompilować wystarczy uruchomić:&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;gcc camera1.cpp -o camera1 -lhighgui&lt;/pre&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;Ten sam przykład po nowemu&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Przykład przedstawiony powyżej działa zarówno w bieżącej wersji&amp;nbsp;&lt;i&gt;OpenCV&lt;/i&gt;&amp;nbsp;jak i w wersjach poprzednich. Jednakże własnie od wersji bieżącej &lt;b&gt;&lt;i&gt;2.2&lt;/i&gt;&lt;/b&gt; biblioteka ta została uporządkowana i podzielona na moduły. Dodatkowo zostały wprowadzone nowe funkcje i został zaproponowany bardziej obiektowy model programowania. Wszystkie te zmiany mają za zadanie ułatwić programowanie, ale nie pozwalają już na kompilację nowych programów tam gdzie jest stara wersja biblioteki. Program po zmianach wg nowych zaleceń wygląda tak:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint lang-cpp notranslate"&gt;#include &amp;lt;opencv2/highgui/highgui.hpp&amp;gt;
#include &amp;lt;opencv2/imgproc/imgproc.hpp&amp;gt;

using namespace cv;

int main(int, char**)
{
  VideoCapture cap(0);
  if( !cap.isOpened() ) return -1;
  
  Mat frame;
  
  const char *window = "Example 2";
  namedWindow(window, CV_WINDOW_AUTOSIZE);
  
  while (cvWaitKey(4) == -1) {
    cap &amp;gt;&amp;gt; frame;
    imshow(window, frame);
  }
  
  return 0;
}&lt;/pre&gt;&lt;br /&gt;
Kompilacja tak napisanego programu w konsoli nie jest już taka trywialna jak poprzednio. W takiej sytuacji najlepiej będzie skorzystać z narzędzia &lt;i&gt;CMake&lt;/i&gt;, które jest podstawą budowania całej biblioteki &lt;i&gt;OpenCV&lt;/i&gt;. W katalogu ze źródłami omawianych aplikacji tworzymy nowy plik&amp;nbsp;&lt;i&gt;CMakeLists.txt&lt;/i&gt;. Powinien on zawierać taką treść:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint lang-cpp notranslate"&gt;PROJECT(opencv_example)

cmake_minimum_required(VERSION 2.8)

FIND_PACKAGE( OpenCV REQUIRED )

# Declare the target (an executable)
ADD_EXECUTABLE(camera1 camera1.cpp)
TARGET_LINK_LIBRARIES(camera1 ${OpenCV_LIBS})

ADD_EXECUTABLE(camera2 camera2.cpp)
TARGET_LINK_LIBRARIES(camera2 ${OpenCV_LIBS})&lt;/pre&gt;&lt;br /&gt;
Teraz już kompilacja sprowadza się do wpisania w konsoli:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;mkdir build
cd build
cmake-gui ../&lt;/pre&gt;&lt;br /&gt;
i określenia w parametrach &lt;i&gt;CMake&lt;/i&gt; ścieżki do katalogu gdzie mamy zbudowany &lt;i&gt;OpenCV&lt;/i&gt;. U mnie wygląda to tak:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;OpenCV_DIR &amp;nbsp; /home/rafal/installed/opencv/OpenCV-2.2.0/build&lt;/pre&gt;&lt;br /&gt;
Teraz już wystarczy wpisać &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;b&gt;make&lt;/b&gt;&lt;/span&gt; i oba programy zostaną skompilowane.&lt;br /&gt;
&lt;br /&gt;
W ten sposób udało nam się przygotować dwie aplikacje, które niby nie robią wiele, ale stanowią szkielet większości aplikacji interaktywnych w &lt;i&gt;OpenCV&lt;/i&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19722740-7314276032471816532?l=rpetryniak.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://rpetryniak.blogspot.com/feeds/7314276032471816532/comments/default" title="Komentarze do posta" /><link rel="replies" type="text/html" href="http://rpetryniak.blogspot.com/2011/03/opencv-instalacja-i-pierwszy-przykad-w.html#comment-form" title="Komentarze (0)" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/19722740/posts/default/7314276032471816532?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/19722740/posts/default/7314276032471816532?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RafalPetryniakBlog/~3/QqUnA0bwauk/opencv-instalacja-i-pierwszy-przykad-w.html" title="OpenCV - instalacja i pierwszy przykład w Ubuntu" /><author><name>Rafał Petryniak</name><uri>https://profiles.google.com/106420849521837640393</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-ueopwOVHATs/AAAAAAAAAAI/AAAAAAAAGaw/TSrE-0eH8Zc/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://rpetryniak.blogspot.com/2011/03/opencv-instalacja-i-pierwszy-przykad-w.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0YCQHo5eyp7ImA9Wx9aEko.&quot;"><id>tag:blogger.com,1999:blog-19722740.post-983311934450967863</id><published>2011-03-03T00:13:00.001+01:00</published><updated>2011-03-04T23:52:41.423+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-03-04T23:52:41.423+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="mobile" /><category scheme="http://www.blogger.com/atom/ns#" term="meego" /><title>Nie do końca udana wirtualizacja MeeGo w VirtualBoxie</title><content type="html">Na początek od razu wyjasnię o co chodzi w tytule, bo wiem, że może on nie zachęcać do czytania dalej. Przez ostatnie kilka dni, mając trochę wolnego czasu postanowiłem przetestować pełną wersję &lt;i&gt;MeeGo Netbook&lt;/i&gt; w środowisku wirtualnym z którego zawsze korzystam, czyli w &lt;i&gt;VirtualBoxie&lt;/i&gt;. Skłoniło mnie do tego nie tylko to, że wersja dostępna w emulatorze &lt;i&gt;QEMU&lt;/i&gt; (jak zainstalować środowisko uruchomieniowe pisałem we wpisie &lt;a href="http://rpetryniak.blogspot.com/2011/02/meego-pierwsze-starcie.html"&gt;MeeGo - pierwsze starcie&lt;/a&gt;) jest mocno okrojona, ale również to, że działa ona dosyć powoli. Miałem nadzieję, że w &lt;i&gt;VirtualBoxie&lt;/i&gt; będzie inaczej, bo to w końcu uznana marka wśród narzędzi do wirtualizacji. Sama instalacja pomimo tego, że nie obyła się bez problemów zakończyła się sukcesem. Niestety problem z powolnym działaniem systemu i brakiem jego responsywności również tutaj był mocno widoczny. Próbowałem różnych sposobów i ostatecznie żaden nie pomógł. Nawet deweloperzy &lt;i&gt;MeeGo&lt;/i&gt; sami twierdzą, że z &lt;i&gt;VirtualBoxem&lt;/i&gt; mogą być problemy i w miarę możliwości zachęcają do instalacji systemu na kompatybilnych urządzeniach. &lt;br /&gt;
&lt;br /&gt;
Pomimo tego, że &lt;i&gt;MeeGo&lt;/i&gt; w &lt;i&gt;VirtualBoxie&lt;/i&gt; nie działa zachwycająco, to dla osób, które nie mają odpowiedniego sprzętu do dyspozycji lub nie chcą instalować kolejnego systemu&amp;nbsp;jedynie w celach testowych&amp;nbsp;na maszynie, na której pracują na co dzień, myślę, że zastosowanie&amp;nbsp;&lt;i&gt;VirtualBoxa&lt;/i&gt; może być dobrym rozwiązaniem. W tym wpisie nie będę szczegółowo rozpisywał się na jakie problemy napotkałem podczas instalacji &lt;i&gt;MeeGo&lt;/i&gt; w &lt;i&gt;VirtualBoxie&lt;/i&gt;, a jedynie przedstawię niezbędne kroki, które pozwolą na instalację i uruchomienie systemu.&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;Pobranie obrazu instalacyjnego&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Płytę z obrazem instalacyjnym &lt;i&gt;MeeGo Netbook&lt;/i&gt; pobieramy ze strony:&amp;nbsp;&lt;a href="http://meego.com/downloads/releases/netbook"&gt;http://meego.com/downloads/releases/netbook&lt;/a&gt;. Ponieważ &lt;i&gt;VirtualBox&lt;/i&gt; nie widzi płyt &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;b&gt;img&lt;/b&gt;&lt;/span&gt; możemy bez żadnego problemu zmienić rozszerzenie pobranego pliku na &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;b&gt;iso&lt;/b&gt;&lt;/span&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;Utworzenie nowej maszyny wirtualnej&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Dalej należy utworzyć pustą maszynę wirtualną. W kreatorze &lt;i&gt;VirtualBoxa&lt;/i&gt;, który do tego służy możemy podać następujące parametry:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;nazwa: &lt;b&gt;MeeGo Netbook v1.1&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;typ systemu: &lt;b&gt;Linux/Fedora&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;pamięć: &lt;b&gt;512MB&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;dysk: &lt;b&gt;dynamicznie rozszerzalny, 8GB&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;Dodatkowo samodzielnie należy wejść do opcji i ustawić parametry jak poniżej:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;System&lt;/span&gt; → &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Procesor&lt;/span&gt; → &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Włącz PAE/NX&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Ekran&lt;/span&gt; → &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Wideo&lt;/span&gt; → &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Włącz akcelerację 3D&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Nośniki&lt;/span&gt; → &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;kontroler IDE&lt;/span&gt; → &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Choose a virtual CD disc file&lt;/span&gt; (wskazujemy na wcześniej pobrany plik z obrazem).&lt;/li&gt;
&lt;/ul&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Instalacja MeeGo NetBook&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Po uruchomieniu systemu wirtualnego powinno nam się pojawić okienko jak poniżej:&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="https://lh5.googleusercontent.com/_AeFiJN9phoM/TW4BdVfZjnI/AAAAAAAAF40/maUvTCjQcL0/meego-virtualbox_1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="https://lh5.googleusercontent.com/_AeFiJN9phoM/TW4BdVfZjnI/AAAAAAAAF40/maUvTCjQcL0/meego-virtualbox_1.png" width="480" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
Wybieramy na nim opcję "&lt;i&gt;Instalation only&lt;/i&gt;". Po chwili czekania powinna się rozpocząć instalacja systemu. Wita nas ona takim obrazkiem:&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="https://lh5.googleusercontent.com/_AeFiJN9phoM/TW4BdpDIzZI/AAAAAAAAF44/-95S9BJaEFI/meego-virtualbox_2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="https://lh5.googleusercontent.com/_AeFiJN9phoM/TW4BdpDIzZI/AAAAAAAAF44/-95S9BJaEFI/meego-virtualbox_2.png" width="480" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
Na kolejnych ekranach wystarczy jedynie ustawić język i skonfigurować dysk. W przypadku pustego dysku wirtualnego nie jest to zbytnio skomplikowane. Potwierdzamy jedynie komunikaty, które się pojawią. O zakończeniu instalacji zostaniemy powiadomieni obrazem jak poniżej:&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="https://lh4.googleusercontent.com/_AeFiJN9phoM/TW4BeI21T5I/AAAAAAAAF5Q/0q8YAuBqMnk/meego-virtualbox_8.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="https://lh4.googleusercontent.com/_AeFiJN9phoM/TW4BeI21T5I/AAAAAAAAF5Q/0q8YAuBqMnk/meego-virtualbox_8.png" width="480" /&gt;&lt;/a&gt;&lt;/div&gt;Kliknięcie na przycisk &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Zamknij&lt;/span&gt; spowoduje restart maszyny wirtualnej. Warto ją w tym momencie w ogóle zatrzymać i odmontować z napędu CD płytę instalacyjną.&lt;br /&gt;
&lt;br /&gt;
Po ponownym uruchomieniu systemu powinniśmy zobaczyć kreator pierwszego uruchomienia. Pyta nas on o ustawienia klawiatury, strefę czasową i prosi o utworzenie użytkownika.&lt;br /&gt;
&lt;br /&gt;
Jeśli system teraz wystartuje to mamy szczęście :-) Ja tego szczęścia niestety nie miałem i zobaczyłem czarny ekran. Po ponownym restarcie komputera wyświetlił mi się tylko obraz tła.&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;Problem przy pierwszym uruchomieniu&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Przy rozwiązywaniu problemów, które zaczęły się pojawiać bardzo pomocna okazała się ta strona na &lt;i&gt;Wiki MeeGo&lt;/i&gt;:&amp;nbsp;&lt;a href="http://wiki.meego.com/MeeGo_1.0_Netbook_VirtualBox"&gt;http://wiki.meego.com/MeeGo_1.0_Netbook_VirtualBox&lt;/a&gt;. Korzystając z porad tam zawartych wykonałem następujące czynności:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Resetujemy maszynę wirtualną i zanim zacznie startować system wciskamy &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Escape&lt;/span&gt;, a następnie &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Tab&lt;/span&gt;.&lt;/li&gt;
&lt;li&gt;Pojawi nam się linijka z tekstem jak na obrazku poniżej, którą możemy wyedytować. Kasujemy tutaj słowo '&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;quiet&lt;/span&gt;' i dodajemy literkę '&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;s&lt;/span&gt;'.&lt;/li&gt;
&lt;/ul&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="https://lh3.googleusercontent.com/_AeFiJN9phoM/TW4Be1rRO7I/AAAAAAAAF5o/kWmCEbD26Xc/meego-virtualbox_15.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="https://lh3.googleusercontent.com/_AeFiJN9phoM/TW4Be1rRO7I/AAAAAAAAF5o/kWmCEbD26Xc/meego-virtualbox_15.png" width="480" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;ul&gt;&lt;li&gt;Klikamy &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Enter&lt;/span&gt; i czekamy. Po chwili powinniśmy zobaczyć wiersz poleceń ze znaczkiem zachęty symbolizującym tryb administracyjny. Skoro już tutaj jesteśmy warto ustawić hasło roota (polecenie '&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;passwd&lt;/span&gt;') i zainstalować 2 przydatne narzędzia (&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;wget&lt;/span&gt; i &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;nano&lt;/span&gt;), które mogą okazać się niezbędne na kolejnych etapach konfiguracji.&lt;br /&gt;
&lt;pre class="prettyprint lang-cpp notranslate"&gt;zypper install wget nano&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;Następnie w konsoli wpisujemy następujące polecenie:&lt;br /&gt;
&lt;pre class="prettyprint lang-cpp notranslate"&gt;chmod +s /usr/bin/Xorg&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;i restartujemy system:&lt;br /&gt;
&lt;pre class="prettyprint lang-cpp notranslate"&gt;reboot&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;div&gt;Teraz system powinien wystartować, ale wcale nie ma takiej pewności :-) U mnie na jednym komputerze opisane podejście zadziałało, a na innym nie przyniosło żadnego rezultatu.&lt;br /&gt;
&lt;br /&gt;
Jeśli system ciągle nie startuje warto sprawdzić, czy nie występuje problem jak ten opisany na forum&amp;nbsp;&lt;i&gt;MeeGo&lt;/i&gt;&amp;nbsp;w wątku:&amp;nbsp;&lt;a href="http://forum.meego.com/showthread.php?t=447"&gt;INIT: Id "x" respawning too fast: disabled&lt;/a&gt;. U mnie właśnie tak było i polecam sprawdzić opisane tam rozwiązanie.&lt;/div&gt;&lt;br /&gt;
Jeśli będziemy mieć szczęście (a na pewno w końcu się uda ;) ) to system powinien &amp;nbsp;wystartować i przywitać nas ekranem jak ten poniżej:&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="https://lh5.googleusercontent.com/_AeFiJN9phoM/TW4BfRBJ2iI/AAAAAAAAF50/GVRsPFHUz1c/meego-virtualbox_20.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="https://lh5.googleusercontent.com/_AeFiJN9phoM/TW4BfRBJ2iI/AAAAAAAAF50/GVRsPFHUz1c/meego-virtualbox_20.png" width="480" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;Próba włączenia wsparcia OpenGL&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Niestety, tak jak wspomniałem na początku,&amp;nbsp;&lt;i&gt;MeeGo&lt;/i&gt; w podstawowej konfiguracji w &lt;i&gt;Virtualboxie&lt;/i&gt; nie zachwyca szybkością - chodzi tak samo ociężale jak wersja dostępna na &lt;i&gt;QEMU&lt;/i&gt;. Na &lt;i&gt;Wiki MeeGo&lt;/i&gt; &lt;a href="http://wiki.meego.com/MeeGo_1.0_Netbook_VirtualBox#Installing_VirtualBox_guest_additions_for_OpenGL_acceleration"&gt;jest rozwiązanie tego problemu&lt;/a&gt;, ale przyznam szczerze, że u mnie nie działa. Testowałem to na kilka sposobów i albo nie było żadnego efektu, albo system nie mógł wystartować. Opiszę jednak kroki, które wykonałem, bo może u kogoś zadziała lub po prostu ktoś będzie w stanie podpowiedzieć mi co źle robiłem.&lt;br /&gt;
&lt;br /&gt;
Po kolei co należy zrobić, aby spróbować uruchomić akcelerację &lt;i&gt;OpenGl&lt;/i&gt; w &lt;i&gt;MeeGo&lt;/i&gt; zainstalowanego w &lt;i&gt;VirtualBox&lt;/i&gt; (w skrócie):&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Uruchamiamy okienko terminala: zakładka Aplikacje → Narzędzia systemowe.&lt;/li&gt;
&lt;li&gt;Instalujemy następujące pakiety i restartujemy system:&lt;br /&gt;
&lt;pre class="prettyprint lang-cpp notranslate"&gt;sudo zypper install gcc make kernel-netbook-devel patch nano wget yum yum-utils 
sudo reboot&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;Instalujemy dodatki&amp;nbsp;&lt;i&gt;VirtualBoxa&lt;/i&gt;. Przed wykonaniem poniższych czynności najpierw należy wybrać w opcjach maszyny:&amp;nbsp;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Urządzenia&lt;/span&gt;&amp;nbsp;→&amp;nbsp;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Zainstaluj dodatki&lt;/span&gt;.&lt;br /&gt;
&lt;pre class="prettyprint lang-cpp notranslate"&gt;sudo mount /dev/sr0 /mnt 
cd /mnt 
sudo ./VBoxLinuxAdditions-x86.run
sudo reboot&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;Tworzymy katalog tymczasowy i próbujemy pobrać źródła C&lt;i&gt;luttera&lt;/i&gt; z repozytorium:&lt;br /&gt;
&lt;pre class="prettyprint lang-cpp notranslate"&gt;cd ~
mkdir tmp
cd tmp
yumdownloader --source clutter&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;Niestety u mnie ta próba kończy się niepowodzeniem. Dostaję komunikat podobny do tego:&lt;/div&gt;&lt;blockquote&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;Error: Cannot retrieve repository metadata (repomd.xml) for repository: meego-core. Please verify its path and try again&amp;nbsp;&lt;/div&gt;&lt;/blockquote&gt;&lt;/li&gt;
&lt;li&gt;Nie pozostaje nam zatem nic innego jak samodzielne pobranie odpowiedniego archiwum ze źródłami&lt;br /&gt;
&lt;pre class="prettyprint lang-cpp notranslate"&gt;wget http://repo.meego.com/MeeGo/releases/1.1/core/repos/source/clutter-1.2.8-2.131.src.rpm
rpm2cpio clutter-1.2.6-2.2.src.rpm|cpio -id
tar jvxf clutter-1.2.6.tar.bz2&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;Następnie pobieramy zależności do zbudowania &lt;i&gt;Cluttera&lt;/i&gt;. Można to zrobić instalując pakiet &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;clutter-devel&lt;/span&gt;, co pozwoli na automatyczne dociągnięcie wszystkich zależnych pakietów:  &lt;br /&gt;
&lt;pre class="prettyprint lang-cpp notranslate"&gt;sudo zypper install clutter-devel&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;Ostatecznie uruchamiamy procedure budowania i instalacji &lt;i&gt;Cluttera&lt;/i&gt;. Między czasie pobieramy i stosujemy dodatkowa łatkę z forum &lt;i&gt;MeeGo&lt;/i&gt;.&lt;br /&gt;
&lt;pre class="prettyprint lang-cpp notranslate"&gt;cd clutter-1.2.8
wget http://wiki.meego.com/images/Clutter-xvisual-patch.txt
patch -p1 &amp;lt; ./Clutter-xvisual-patch.txt
./configure --prefix=/usr
make
sudo make install
reboot&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;Po wykonaniu opisanych czynności restartujemy komputer. Należ się również upewnić, że jest włączona akceleracja 3D w ustawieniach &lt;i&gt;VirtualBoxa&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;Prezentacja systemu&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Na koniec wpisu załączam małą galerię slajdów wykonanych nie tylko na kolejnych etapach instalacji i konfiguracji &lt;i&gt;MeeGo&lt;/i&gt; w &lt;i&gt;Virtualboxie&lt;/i&gt;, ale również slajdy prezentujące wygląd poszczególnych ekranów systemu.&lt;br /&gt;
&lt;br /&gt;
&lt;div style="font-family: arial,sans-serif; font-size: 13px; width: 600px;"&gt;&lt;div&gt;&lt;embed flashvars="host=picasaweb.google.com&amp;amp;noautoplay=1&amp;amp;hl=pl&amp;amp;feat=flashalbum&amp;amp;RGB=0x000000&amp;amp;feed=https%3A%2F%2Fpicasaweb.google.com%2Fdata%2Ffeed%2Fapi%2Fuser%2Frpetryniak%2Falbumid%2F5579398298530844945%3Falt%3Drss%26kind%3Dphoto%26hl%3Dpl" height="400" pluginspage="http://www.macromedia.com/go/getflashplayer" src="https://picasaweb.google.com/s/c/bin/slideshow.swf" type="application/x-shockwave-flash" width="600"&gt;&lt;/embed&gt;&lt;/div&gt;&lt;span style="float: left;"&gt;&lt;a href="https://picasaweb.google.com/rpetryniak/MeeGoWVirtualBox?feat=flashalbum" style="color: #3964c2;"&gt;Wyświetl wszystkie&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div style="text-align: right;"&gt;&lt;a href="http://picasaweb.google.com/lh/getEmbed?feat=flashalbum" style="color: #3964c2;"&gt;Uzyskaj własny&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19722740-983311934450967863?l=rpetryniak.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://rpetryniak.blogspot.com/feeds/983311934450967863/comments/default" title="Komentarze do posta" /><link rel="replies" type="text/html" href="http://rpetryniak.blogspot.com/2011/03/nie-do-konca-udana-wirtualizacja-meego.html#comment-form" title="Komentarze (2)" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/19722740/posts/default/983311934450967863?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/19722740/posts/default/983311934450967863?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RafalPetryniakBlog/~3/O_Nnp6IrTLI/nie-do-konca-udana-wirtualizacja-meego.html" title="Nie do końca udana wirtualizacja MeeGo w VirtualBoxie" /><author><name>Rafał Petryniak</name><uri>https://profiles.google.com/106420849521837640393</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-ueopwOVHATs/AAAAAAAAAAI/AAAAAAAAGaw/TSrE-0eH8Zc/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://lh5.googleusercontent.com/_AeFiJN9phoM/TW4BdVfZjnI/AAAAAAAAF40/maUvTCjQcL0/s72-c/meego-virtualbox_1.png" height="72" width="72" /><thr:total>2</thr:total><feedburner:origLink>http://rpetryniak.blogspot.com/2011/03/nie-do-konca-udana-wirtualizacja-meego.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0YCQHo5fCp7ImA9Wx9aEko.&quot;"><id>tag:blogger.com,1999:blog-19722740.post-3163909263803624768</id><published>2011-02-25T00:19:00.001+01:00</published><updated>2011-03-04T23:52:41.424+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-03-04T23:52:41.424+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="mobile" /><category scheme="http://www.blogger.com/atom/ns#" term="meego" /><title>Pierwsza mobilna aplikacja dla MeeGo</title><content type="html">Witam. Podobnie jak w przypadku&amp;nbsp;poprzednich&amp;nbsp;dwóch postów, dzisiaj również ostrzegam :-), że nie będzie nic odkrywczego względem &lt;a href="http://wiki.meego.com/SDK/Docs/1.1"&gt;oficjalnego Wiki dla programistów MeeGo&lt;/a&gt;.&amp;nbsp;Pomimo tego, że sporo korzystam z materiałów tam zawartych, to moje wpisy nie są ich tłumaczeniami, ale raczej opisem własnych doświadczeń z testowania dostępnych tam poradników.&lt;br /&gt;
&lt;br /&gt;
Tym razem będzie o tym jak napisać, skompilować i uruchomić swoją pierwszą aplikacje mobilną dla &lt;i&gt;MeeGo&lt;/i&gt;. Wpis ten jest mocno inspirowany następującą stroną na &lt;i&gt;Wiki MeeGo&lt;/i&gt;:&lt;br /&gt;
&lt;a href="http://wiki.meego.com/SDK/Docs/1.1/Creating_Hello_World"&gt;http://wiki.meego.com/SDK/Docs/1.1/Creating_Hello_World&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Zakładam na początek, że mamy już &lt;a href="http://rpetryniak.blogspot.com/2011/02/meego-pierwsze-starcie.html"&gt;zainstalowane środowisko wdrożeniowe i uruchomieniowe&lt;/a&gt;&amp;nbsp;oraz, że została przeprowadzona wymagana &lt;a href="http://rpetryniak.blogspot.com/2011/02/meego-sdk-konfiguracja-qt-creator.html"&gt;konfiguracja Qt Creatora&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
W pierwszym momencie - zapewne jak się nie trudno domyśleć, należy uruchomić &lt;i&gt;Qt Creatora&lt;/i&gt;. W następnym kroku przystępujemy do stworzenia nowego projektu wybierając odpowiednio w menu &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Plik&lt;/span&gt; → &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Nowy plik lub projekt&lt;/span&gt; → &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Mobilna aplikacja Qt&lt;/span&gt;. Potwierdzamy klikając &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Wybierz…&lt;/span&gt; .&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="https://lh5.googleusercontent.com/_AeFiJN9phoM/TWbN_4a_ojI/AAAAAAAAF2s/sgNGaafQk70/meego-pierwsza_aplikacja_w_qt_1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="https://lh5.googleusercontent.com/_AeFiJN9phoM/TWbN_4a_ojI/AAAAAAAAF2s/sgNGaafQk70/meego-pierwsza_aplikacja_w_qt_1.png" width="430" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
Określamy następnie nazwę projektu i wybieramy jego docelową lokalizację.&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="https://lh6.googleusercontent.com/_AeFiJN9phoM/TWbOANbvgFI/AAAAAAAAF24/tTbhJbclVX8/meego-pierwsza_aplikacja_w_qt_2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="https://lh6.googleusercontent.com/_AeFiJN9phoM/TWbOANbvgFI/AAAAAAAAF24/tTbhJbclVX8/meego-pierwsza_aplikacja_w_qt_2.png" width="430" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
W kolejnym kroku wybieramy jako wersję &lt;i&gt;Qt&lt;/i&gt; tą dostępną po instalacji &lt;i&gt;MeeGo SDK&lt;/i&gt;.&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="https://lh4.googleusercontent.com/_AeFiJN9phoM/TWbN_-eukiI/AAAAAAAAF2w/vtvG0SfyQ78/meego-pierwsza_aplikacja_w_qt_3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="https://lh4.googleusercontent.com/_AeFiJN9phoM/TWbN_-eukiI/AAAAAAAAF2w/vtvG0SfyQ78/meego-pierwsza_aplikacja_w_qt_3.png" width="430" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
Możemy również zmienić domyślne nazwy plików, ale skoro ma to być tylko aplikacja testowa polecam pozostawienie tych zaproponowanych przez kreatora.&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="https://lh6.googleusercontent.com/_AeFiJN9phoM/TWbOAGmDtWI/AAAAAAAAF20/Hsjufe_fsFY/meego-pierwsza_aplikacja_w_qt_4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="https://lh6.googleusercontent.com/_AeFiJN9phoM/TWbOAGmDtWI/AAAAAAAAF20/Hsjufe_fsFY/meego-pierwsza_aplikacja_w_qt_4.png" width="430" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
Ostatecznie dostajemy ogólne podsumowanie nowo utworzonego projektu:&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="https://lh5.googleusercontent.com/_AeFiJN9phoM/TWbfV1s_SiI/AAAAAAAAF30/1hzEuPmkpeU/meego-pierwsza_aplikacja_w_qt_5.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="https://lh5.googleusercontent.com/_AeFiJN9phoM/TWbfV1s_SiI/AAAAAAAAF30/1hzEuPmkpeU/meego-pierwsza_aplikacja_w_qt_5.png" width="430" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
Prawdopodobnie &lt;i&gt;Qt Creator&lt;/i&gt; otworzy się w trybie projektowania interfejsu, dlatego przełączamy się do trybu &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Edycji&lt;/span&gt; kodu źródłowego. Posługując się nawigatorem projektu otwieramy plik &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;main.cpp&lt;/span&gt;&amp;nbsp;i zamieniamy jego zawartość na następującą:&lt;br /&gt;
&lt;pre class="prettyprint lang-cpp notranslate"&gt;#include &amp;lt;qapplication&amp;gt;
#include &amp;lt;qlabel&amp;gt;
#include &amp;lt;qsysteminfo&amp;gt;
using namespace QtMobility;

int main(int argc, char *argv[])
{
  QApplication app(argc, argv);
  QSystemInfo s;
  QLabel *label = new QLabel(QObject::tr("hello").
    append(s.currentCountryCode()));
  label-&amp;gt;show();
  label-&amp;gt;resize(100,30);
  return app.exec();
}&lt;/pre&gt;&lt;br /&gt;
Teraz należy&amp;nbsp;wyedytować&amp;nbsp;plik z ustawieniami projektu &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;*.pro&lt;/span&gt; dodając do niego następujące wpisy:&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;CONFIG += mobility
MOBILITY += systeminfo&lt;/pre&gt;&lt;br /&gt;
Aby zapisać wszystkie wprowadzone zmiany najlepiej skorzystać z menu &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Plik&lt;/span&gt; → &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Zachowaj wszystko&lt;/span&gt;.&lt;br /&gt;
&lt;br /&gt;
Przed uruchomieniem przygotowanej aplikacji należy najpierw przejść do zakładki &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Projekty&lt;/span&gt; i tam na zakładce&amp;nbsp;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Produkty docelowe&lt;/span&gt; wybrać&amp;nbsp;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;MeeGo&lt;/span&gt; i &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Uruchom&lt;/span&gt;.&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="https://lh6.googleusercontent.com/_AeFiJN9phoM/TWbOAUMysJI/AAAAAAAAF28/wcsr2cv_90o/meego-pierwsza_aplikacja_w_qt_6.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="https://lh6.googleusercontent.com/_AeFiJN9phoM/TWbOAUMysJI/AAAAAAAAF28/wcsr2cv_90o/meego-pierwsza_aplikacja_w_qt_6.png" width="500" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
Tutaj należy określić jedynie&amp;nbsp;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Device configuration&lt;/span&gt;, gdzie powinniśmy wskazać na skonfigurowane wcześniej środowisko uruchomieniowe (jak to zrobić pisałem we wpisie "&lt;a href="http://rpetryniak.blogspot.com/2011/02/meego-sdk-konfiguracja-qt-creator.html"&gt;MeeGo SDK - Konfiguracja Qt Creator&lt;/a&gt;", w sekcji "&lt;i&gt;Dostęp do środowiska uruchomieniowego MeeGo&lt;/i&gt;"). U mnie to jest akurat:&amp;nbsp;&lt;b&gt;MeeGo NetBook Emulator&lt;/b&gt;. Oczywiście &lt;u&gt;należy pamiętać o tym, aby wystartować wybrane środowisko uruchomieniowe &lt;i&gt;MeeGo&lt;/i&gt;&lt;/u&gt;. Możemy to zrobić wpisując w konsoli polecenie tego typu:&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;sudo mad remote -r meego-netbook-ia32-qemu-1.1.2-runtime poweron&lt;/pre&gt;&lt;br /&gt;
Po tym wszystkim możemy uruchomić projekt klikając na zielony "trójkącik" symbolizujący start aplikacji. Prawdopodobnie w konsoli &lt;i&gt;Qt Creatora&lt;/i&gt; zobaczymy komunikat podobny do tego:&lt;br /&gt;
&lt;blockquote&gt;Cleaning up remote leftovers first ...&lt;br /&gt;
Initial cleanup done.&lt;br /&gt;
Files to deploy: /home/rafal/qthello-build-meego/rrpmbuild/qthello-0.0.1-1.i586.rpm.&lt;br /&gt;
Deployment finished.&lt;br /&gt;
Starting remote application.&lt;br /&gt;
access control disabled, clients can connect from any host&lt;br /&gt;
Could not find Hal&lt;br /&gt;
Could not find Hal&lt;/blockquote&gt;Teoretycznie teraz powinniśmy zobaczyć w testowym środowisku &lt;i&gt;MeeGo&lt;/i&gt;&amp;nbsp;wystartowaną aplikację. Ja niestety na pierwszy rzut oka nie dostrzegłem żadnych zmian. Po kilku kliknięciach w interfejs zauważyłem, że aplikacja jest jednak uruchomiona, ale znajduje się "w tle". Aby zobaczyć ją na pełnym ekranie wystarczy kliknąć na pierwszą zakładkę - tą z domkiem, symbolizującą strefę &lt;i&gt;MyZones&lt;/i&gt; (widać to na rysunku poniżej).&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="https://lh4.googleusercontent.com/_AeFiJN9phoM/TWbOZs5PBCI/AAAAAAAAF3U/RKvxbEtER8c/meego-pierwsza_aplikacja_w_qt_7.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="https://lh4.googleusercontent.com/_AeFiJN9phoM/TWbOZs5PBCI/AAAAAAAAF3U/RKvxbEtER8c/meego-pierwsza_aplikacja_w_qt_7.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
Teraz już powinniśmy zobaczyć naszą pierwszą&amp;nbsp;mobilną&amp;nbsp;aplikację dla MeeGo :-D :&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="https://lh4.googleusercontent.com/_AeFiJN9phoM/TWbOZlZvR5I/AAAAAAAAF3Y/N-RUbvWTOGA/meego-pierwsza_aplikacja_w_qt_8.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="https://lh4.googleusercontent.com/_AeFiJN9phoM/TWbOZlZvR5I/AAAAAAAAF3Y/N-RUbvWTOGA/meego-pierwsza_aplikacja_w_qt_8.png" width="500" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
Czy miałem podczas wykonywania tych kroków jakieś błędy? Tak, był jeden, ale był on związany z tym, że próbowałem uruchomić aplikację w &lt;i&gt;Qt Creatorze&lt;/i&gt; nie mając wcześniej wystartowanego środowiska testowego. Dostałem wówczas taki komunikat:&lt;br /&gt;
&lt;blockquote&gt;Cleaning up remote leftovers first ...&lt;br /&gt;
Error running initial cleanup: Nie można połączyć się z hostem.&lt;/blockquote&gt;Jeśli będą pojawiać się inne komunikaty i inne błędy, polecam najpierw upewnić się, że &lt;i&gt;Qt Creator&lt;/i&gt; poprawnie łączy się z środowiskiem uruchomieniowym &lt;i&gt;MeeGo&lt;/i&gt;. Można to sprawdzić przechodząc odpowiednio do&amp;nbsp;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Narzędzia&lt;/span&gt; → &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Opcje&lt;/span&gt; → &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Projekty&lt;/span&gt; → &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;MeeGo Device Configuration&lt;/span&gt; i tam wybierając z listy wcześniej przygotowaną konfigurację możemy skorzystać z opcji &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Test&lt;/span&gt;. Jeśli tutaj wszystko pójdzie OK, nie powinno być problemów z wystartowaniem aplikacji.&lt;br /&gt;
&lt;br /&gt;
Mamy już pierwszą aplikację. Co dalej? Czekam na sugestie czytelników o czym chcieli by poczytać :-).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19722740-3163909263803624768?l=rpetryniak.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://rpetryniak.blogspot.com/feeds/3163909263803624768/comments/default" title="Komentarze do posta" /><link rel="replies" type="text/html" href="http://rpetryniak.blogspot.com/2011/02/pierwsza-mobilna-aplikacja-dla-meego.html#comment-form" title="Komentarze (0)" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/19722740/posts/default/3163909263803624768?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/19722740/posts/default/3163909263803624768?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RafalPetryniakBlog/~3/nyTrLqtKKB8/pierwsza-mobilna-aplikacja-dla-meego.html" title="Pierwsza mobilna aplikacja dla MeeGo" /><author><name>Rafał Petryniak</name><uri>https://profiles.google.com/106420849521837640393</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-ueopwOVHATs/AAAAAAAAAAI/AAAAAAAAGaw/TSrE-0eH8Zc/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://lh5.googleusercontent.com/_AeFiJN9phoM/TWbN_4a_ojI/AAAAAAAAF2s/sgNGaafQk70/s72-c/meego-pierwsza_aplikacja_w_qt_1.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://rpetryniak.blogspot.com/2011/02/pierwsza-mobilna-aplikacja-dla-meego.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0YCQHo5fyp7ImA9Wx9aEko.&quot;"><id>tag:blogger.com,1999:blog-19722740.post-6314686846273547473</id><published>2011-02-21T20:43:00.001+01:00</published><updated>2011-03-04T23:52:41.427+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-03-04T23:52:41.427+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="mobile" /><category scheme="http://www.blogger.com/atom/ns#" term="meego" /><title>MeeGo SDK - Konfiguracja Qt Creator</title><content type="html">Instalując &lt;i&gt;MeeGo SDK&lt;/i&gt; (&lt;a href="http://rpetryniak.blogspot.com/2011/02/meego-pierwsze-starcie.html"&gt;pisałem o tym więcej w poprzednim wpisie&lt;/a&gt;) dostajemy pełne środowisko programistyczne, które zawiera nie tylko wymagane biblioteki i środowisko uruchomieniowe, ale również wygodne narzędzie do programowania: &lt;i&gt;Qt Creator&lt;/i&gt;. Jest to w pełni funkcjonalne środowisko programistyczne dla &lt;i&gt;Qt&lt;/i&gt;, które zawiera wiele wygodnych mechanizmów ułatwiających wykonywanie często żmudnych czynności: pełna obsługa kilku systemów śledzenia wersji, wspomaganie procesu kompilacji, narzędzia do testowania i debugowania, zintegrowaną dokumentację, kolorowanie składni i wiele innych. Narzędzie to zostało również przystosowane przez firmę &lt;i&gt;Nokia&lt;/i&gt; do programowania pod platformę &lt;i&gt;MeeGo&lt;/i&gt;. Wystarczy wskazać i skonfigurować dostęp do środowiska wdrożeniowego (&lt;i&gt;MeeGo Target&lt;/i&gt;) oraz środowiska uruchomieniowego (&lt;i&gt;MeeGo Runtime&lt;/i&gt;), aby łatwo zacząć programować aplikacje mobilne i tym się właśnie zajmę w dzisiejszym wpisie. Od razu na początku wspomnę, że wszystkie opisane w tym poradniku kroki są bardzo dobrze opisane na &lt;i&gt;Wiki projektu&lt;/i&gt;, na&amp;nbsp;którym się wzorowałem. W razie problemów polecam zajrzeć na strony:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;a href="http://wiki.meego.com/SDK/Docs/1.1/Getting_started_with_the_MeeGo_SDK_for_Linux#Configuring_Qt_Creator_to_use_the_MeeGo_toolchain.28s.29"&gt;Configuring Qt Creator to use the MeeGo toolchain(s)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://wiki.meego.com/SDK/Docs/1.1/Configuring_QEMU_runtimes#Configuring_access_to_an_emulated_device_in_Qt_Creator"&gt;Configuring access to an emulated device in Qt Creator&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Konfiguracja narzędzi kompilujących i bibliotek &lt;/span&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;&lt;i&gt;MeeGo&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Aby skonfigurować w &lt;i&gt;Qt Creator&lt;/i&gt; dostęp o narzędzi kompilujących i bibliotek &lt;i&gt;MeeGo&lt;/i&gt; (tzw. &lt;i&gt;MeeGo Toolchain&lt;/i&gt;) wykonujemy następujące czynności:&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;Uruchamiamy &lt;i&gt;Qt Creator&lt;/i&gt;. Może&amp;nbsp;to&amp;nbsp;być ten dostarczony z &lt;i&gt;MeeGo&lt;/i&gt;, lub ten z którego do tej pory korzystaliśmy w systemie (najlepiej oczywiście jakby była to najnowsza dostępna wersja, aby mieć pewność, że będzie wspierała&amp;nbsp;&lt;i&gt;MeeGo&lt;/i&gt;). Ja wybrałem to drugie podejście, aby nie rozdrabniać sobie środowiska programistycznego. Zresztą na stronie Wiki również tak proponują.&lt;/li&gt;
&lt;li&gt;Wchodzimy do &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Narzędzia&lt;/span&gt; → &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Opcje&lt;/span&gt; → &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Qt4&lt;/span&gt; → &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Wersje Qt&lt;/span&gt;.&lt;/li&gt;
&lt;li&gt;Po prawej stronie zakładki &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Wersje Qt&lt;/span&gt; klikamy przycisk z plusikiem, aby dodać nową wersję.&lt;/li&gt;
&lt;li&gt;W polu &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Nazwa wersji&lt;/span&gt; wpisujemy własną nazwę określającą wersję &lt;i&gt;Qt&lt;/i&gt;. Może to być np. &lt;b&gt;MeeGo NetBook IA32 1.1.2&lt;/b&gt;.&lt;/li&gt;
&lt;li&gt;Podajemy również ścieżkę do &lt;i&gt;qmake&lt;/i&gt; zainstalowanego w katalogach &lt;i&gt;MeeGo&lt;/i&gt;. W moim systemie 64-bitowym było to akurat &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;/usr/lib/madde/linux-x86_64/targets/meego-netbook-ia32-1.1.2/bin/qmake&lt;/span&gt;. Z dokumentacji wynika, że dla architektur 32-bitowych powinno to być podobnie do &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;/usr/lib/madde/linux-i686/targets/meego-netbook-ia32-1.1.2/bin/qmake&lt;/span&gt;, jednak nie mam co do tego pewności i polecam sprawdzić samodzielnie.&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="https://lh6.googleusercontent.com/_AeFiJN9phoM/TWKcLobBHhI/AAAAAAAAF0g/13zF0AZzN0E/meego-dev-qtcreator_1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="216" src="https://lh6.googleusercontent.com/_AeFiJN9phoM/TWKcLobBHhI/AAAAAAAAF0g/13zF0AZzN0E/meego-dev-qtcreator_1.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;Klikamy &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Przebuduj&lt;/span&gt;, &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Zastosuj&lt;/span&gt; i &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Ok&lt;/span&gt;.&lt;/li&gt;
&lt;li&gt;Aby zobaczyć więcej informacji o własnie skonfigurowanej wersji &lt;i&gt;Qt&lt;/i&gt; wystarczy jeszcze raz wejść do tego samego okienka i kliknąć oraz przytrzymać wskaźnik myszy na etykiecie &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Ustawienia ręczne&lt;/span&gt; → &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;MeeGo NetBook IA32 1.1.2&lt;/span&gt;. Powininny się wyświetlić informacje podobne jak na rysunku poniżej.&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="https://lh5.googleusercontent.com/_AeFiJN9phoM/TWKcL17jWII/AAAAAAAAF0k/ZhhoYQ8d9CA/meego-dev-qtcreator_2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="320" src="https://lh5.googleusercontent.com/_AeFiJN9phoM/TWKcL17jWII/AAAAAAAAF0k/ZhhoYQ8d9CA/meego-dev-qtcreator_2.png" width="262" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ol&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Dostęp do środowiska uruchomieniowego &lt;i&gt;MeeGo&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Aby skonfigurować dostęp do wybranego środowiska uruchomieniowego &lt;i&gt;MeeGo&lt;/i&gt; (tzw. &lt;i&gt;MeeGo Runtime&lt;/i&gt;) z poziomu &lt;i&gt;Qt Creatora&lt;/i&gt; wystarczy wykonać następujące czynności:&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;Otwieramy &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Narzędzia&lt;/span&gt; → &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Opcje&lt;/span&gt; → &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Projekty&lt;/span&gt; → &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;MeeGo Device Configuration&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;i klikamy tutaj przycisk &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Add&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;Warto ustalić od razu nazwę dla tej konfiguracji. Może to być np. &lt;b&gt;MeeGo NetBook Emulator&lt;/b&gt;.&lt;/li&gt;
&lt;li&gt;Uzupełniamy pozostałe pola (przykład na rysunku poniżej):&lt;/li&gt;
&lt;ul&gt;&lt;li&gt;Device type: &lt;b&gt;MeeGo emulator&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;Authentication type: &lt;b&gt;Password&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;Host name: &lt;b&gt;localhost&lt;/b&gt; (wartość domyślna)&lt;/li&gt;
&lt;li&gt;SSH port: &lt;b&gt;6666&lt;/b&gt; (wartość domyślna)&lt;/li&gt;
&lt;li&gt;Gdb serwer port: &lt;b&gt;13219&lt;/b&gt; (wartość domyślna)&lt;/li&gt;
&lt;li&gt;Connection timeout: &lt;b&gt;30s&amp;nbsp;&lt;/b&gt;(wartość domyślna)&lt;/li&gt;
&lt;li&gt;Username: &lt;b&gt;root&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;Password: &lt;b&gt;meego&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;li&gt;Klikamy&amp;nbsp;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Zastosuj&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="https://lh3.googleusercontent.com/_AeFiJN9phoM/TWKcMGYI91I/AAAAAAAAF0o/hMXD4HRO4oE/meego-dev-qtcreator_3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="216" src="https://lh3.googleusercontent.com/_AeFiJN9phoM/TWKcMGYI91I/AAAAAAAAF0o/hMXD4HRO4oE/meego-dev-qtcreator_3.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;Aby przetestować właśnie skonfigurowane ustawienia należy najpierw uruchomić wybrane środowisko - można to zrobić wpisując w konsoli:&lt;br /&gt;
&lt;pre class="prettyprint lang-cpp notranslate"&gt;sudo mad remote -r meego-netbook-ia32-qemu-1.1.2-runtime poweron&lt;/pre&gt;a następnie klikając przycisk &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Test&lt;/span&gt; w okienku &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;MeeGo Device Configuration&lt;/span&gt;. Jeśli wszystko jest OK powinniśmy zobaczyć okienko takie jak na zrzucie poniżej:&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="https://lh4.googleusercontent.com/_AeFiJN9phoM/TWKcMG9tSdI/AAAAAAAAF0s/8Zd_w6Luupw/meego-dev-qtcreator_4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="320" src="https://lh4.googleusercontent.com/_AeFiJN9phoM/TWKcMG9tSdI/AAAAAAAAF0s/8Zd_w6Luupw/meego-dev-qtcreator_4.png" width="206" /&gt;&lt;/a&gt;&lt;/div&gt;Co z tego wynika i po co to wszystko opiszę w kolejnym wpisie z przykładem pierwszej aplikacji dla &lt;i&gt;MeeGo&amp;nbsp;&lt;/i&gt;:-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19722740-6314686846273547473?l=rpetryniak.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://rpetryniak.blogspot.com/feeds/6314686846273547473/comments/default" title="Komentarze do posta" /><link rel="replies" type="text/html" href="http://rpetryniak.blogspot.com/2011/02/meego-sdk-konfiguracja-qt-creator.html#comment-form" title="Komentarze (0)" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/19722740/posts/default/6314686846273547473?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/19722740/posts/default/6314686846273547473?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RafalPetryniakBlog/~3/hLjmyyEulZE/meego-sdk-konfiguracja-qt-creator.html" title="MeeGo SDK - Konfiguracja Qt Creator" /><author><name>Rafał Petryniak</name><uri>https://profiles.google.com/106420849521837640393</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-ueopwOVHATs/AAAAAAAAAAI/AAAAAAAAGaw/TSrE-0eH8Zc/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://lh6.googleusercontent.com/_AeFiJN9phoM/TWKcLobBHhI/AAAAAAAAF0g/13zF0AZzN0E/s72-c/meego-dev-qtcreator_1.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://rpetryniak.blogspot.com/2011/02/meego-sdk-konfiguracja-qt-creator.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0YCQHo5cSp7ImA9Wx9aEko.&quot;"><id>tag:blogger.com,1999:blog-19722740.post-5936590133404530293</id><published>2011-02-18T22:17:00.002+01:00</published><updated>2011-03-04T23:52:41.429+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-03-04T23:52:41.429+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="mobile" /><category scheme="http://www.blogger.com/atom/ns#" term="meego" /><title>MeeGo - pierwsze starcie</title><content type="html">Głośno w ostatnim czasie zrobiło się o &lt;i&gt;&lt;b&gt;MeeGo&lt;/b&gt;&lt;/i&gt; i to nie za sprawą wysypu urządzeń z tą platformą mobilną, a wręcz przeciwnie - ostatnia decyzja kluczowego partnera projektu, &lt;i&gt;Nokii&lt;/i&gt; o &lt;a href="http://www.heise-online.pl/newsticker/news/item/Nokia-i-Microsoft-lacza-sily-1188203.html"&gt;wyborze Windows Phone 7&lt;/a&gt; jako głównego systemu dla kolejnych generacji smartfonów &amp;nbsp;postawiła duży znak zapytania co do przyszłości rozwoju &lt;i&gt;MeeGo&lt;/i&gt;. &amp;nbsp;Na szczęści drugi duży partner w rozwoju &lt;i&gt;MeeGo&lt;/i&gt; - &lt;i&gt;Intel&lt;/i&gt;, &lt;a href="http://www.heise-online.pl/newsticker/news/item/Intel-wciaz-stawia-na-MeeGo-i-obiecuje-32-nanometrowy-procesor-Atom-1189676.html"&gt;zamierza ciągle intensywnie inwestować w tą platformę&lt;/a&gt; i &lt;a href="http://www.heise-online.pl/open/news/item/MeeGo-Intel-poszuka-innych-partnerow-1192918.html"&gt;zachęca do tego również inne firmy&lt;/a&gt;. A tych &lt;a href="http://www.linuxfoundation.org/node/6144"&gt;&lt;span id="goog_1427157054"&gt;&lt;/span&gt;firm już teraz jest sporo&lt;span id="goog_1427157055"&gt;&lt;/span&gt;&lt;/a&gt;. Do firm, które zadeklarował sie wspierać i używać &lt;i&gt;MeeGo&lt;/i&gt; w swoich produktach mozna wyróżnić nie tylko takich gigantów branży elektronicznej jak &lt;i&gt;AMD&lt;/i&gt;, &lt;i&gt;Asus&lt;/i&gt;, &lt;i&gt;Acer&lt;/i&gt;, &lt;i&gt;Cisco&lt;/i&gt;, ale również wiele innych firm na czele z &lt;i&gt;BMW&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
Ja od dawna kibicuję &lt;i&gt;MeeGo&lt;/i&gt;, aby jak najszybciej weszło i zdobyło rynek urządzeń mobilnych i multimedialnych. Głównym powodem jest to, że bardzo wygodnie pracuje mi się z biblioteką &lt;a href="http://rpetryniak.blogspot.com/2008/08/qt_20.html"&gt;&lt;i&gt;Qt&lt;/i&gt;&lt;/a&gt;, a myśl, że program, który napiszę w &lt;i&gt;Linuksie&lt;/i&gt; będzie działał nie tylko na &lt;i&gt;MS Window&lt;/i&gt; i &lt;i&gt;Mac iOS,&lt;/i&gt; jak to miało miejsce dotychczas, ale również na wszystkich urządzeniach obsługujących &lt;i&gt;MeeGo&lt;/i&gt; wydaje się naprawdę ekscytująca. Ostatnie decyzje &lt;i&gt;Nokii&lt;/i&gt; również mnie nie wprawiły w najlepsze samopoczucie, ale już zdążyłem ochłonąć :) i wiem, że najlepszą rzeczą, którą mogę w takim momencie zrobić to promować tą platformę i zachęcać do niej innych. W związku z tym chciałbym rozpocząć serię artykułów&amp;nbsp;pokazujących jak rozpocząć przygodę z tym systemem.&amp;nbsp;Od razu również dodam, że do tej pory nie miałem żadnego doświadczenia z &lt;i&gt;MeeGo&lt;/i&gt; i &amp;nbsp;moje wpisy raczej będą opisywać pierwsze kroki, które sam postawiłem, a nie zaawansowane zagadnienia z punktu widzenia eksperta w tej dziedzinie. &lt;br /&gt;
&lt;br /&gt;
Na początek przygotowałem mały poradnik jak zainstalować podstawowe środowisko uruchomieniowe i jak&amp;nbsp;skonfigurować zestaw narzędzi, które będą niezbędne do implementacji własnych programów. Poradnik ten został przygotowany w oparciu o oficjalną dokumentację znajdująca się na &lt;i&gt;Wiki&lt;/i&gt; projektu: &lt;a href="http://wiki.meego.com/SDK/Docs/1.1/Getting_started_with_the_MeeGo_SDK_for_Linux"&gt;http://wiki.meego.com/SDK/Docs/1.1/&lt;/a&gt;&lt;br /&gt;
&lt;a href="http://wiki.meego.com/SDK/Docs/1.1/Getting_started_with_the_MeeGo_SDK_for_Linux"&gt;Getting_started_with_the_MeeGo_SDK_for_Linux&lt;/a&gt;. Jest ona naprawdę dobrze przygotowana i mój opis będzie raczej jej skrótem, a nie rozwinięciem. Wszystkie instrukcje zostaną pokazane na przykladzie systemu &lt;b&gt;&lt;i&gt;Ubuntu w wersji 10.10&lt;/i&gt;&lt;/b&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;Ustawienie repozytorium&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Wielkim ułatwieniem dla osób interesujących się testowaniem i rozwojem &lt;i&gt;MeeGo&lt;/i&gt; w &lt;i&gt;Ubuntu&lt;/i&gt; jest przygotowane dla tej dystrybucji repozytorium, które zawiera wszystkie niezbędne narzędzia do dalszej pracy. Konfigurujemy je w sposób opisany poniżej.&lt;br /&gt;
&lt;br /&gt;
Tworzymy nowy plik&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;sudo nano /etc/apt/sources.list.d/meego-sdk.list&lt;/pre&gt;do którego zapisujemy:&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;deb http://repo.meego.com/MeeGo/sdk/host/repos/ubuntu/10.10/   /&lt;/pre&gt;&lt;br /&gt;
Pobieramy klucze do repozytorium:&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;gpg --keyserver pool.sks-keyservers.net --recv 0BC7BEC479FC1F8A
gpg --export --armor 0BC7BEC479FC1F8A | sudo apt-key add -&lt;/pre&gt;&lt;br /&gt;
Aktualizujemy listę pakietów:&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;sudo apt-get update&lt;/pre&gt;&lt;br /&gt;
Sprawdzamy poprawność repozytorium:&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;apt-cache policy madde&lt;/pre&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;Instalacja MeeGo SDK&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Aby zainstalować pakiet narzędzi &lt;i&gt;MeeGoo&lt;/i&gt; (tzw. &lt;i&gt;SDK&lt;/i&gt;) wystarczy wskazać do instalacji meta-pakiet &lt;b&gt;&lt;i&gt;meego-sdk&lt;/i&gt;&lt;/b&gt;. Dzięki temu wszystkie wymagane pakiety zostaną zainstalowane.&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;sudo apt-get install meego-sdk&lt;/pre&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;Instalacja środowiska wdrożeniowego (&lt;i&gt;Target&lt;/i&gt;)&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Należy również zainstalować wybrane środowisko wdrożeniowe &lt;i&gt;MeeGo&lt;/i&gt; (tzw. &lt;i&gt;MeeGoo Target&lt;/i&gt;). W jego skład wchodzi zestaw aplikacji do kompilacji, linkowania i debugowania (tzw. &lt;i&gt;MeeGoo Toolchain&lt;/i&gt;) oraz biblioteki systemowe.&lt;br /&gt;
&lt;br /&gt;
Aby sprawdzić jakie środowiska wdrożeniowe mamy do dyspozycji wydajemy polecenie:&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;sudo mad-admin list&lt;/pre&gt;&lt;br /&gt;
Ja wybrałem do instalacji dwa z nich:&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;sudo mad-admin create -f meego-netbook-ia32-1.1.2
sudo mad-admin create -f meego-handset-ia32-1.1.2&lt;/pre&gt;&lt;br /&gt;
Aby przetestować działanie wybranego środowiska, warto utworzyć dla niego przykładową aplikację. Można to szybko zrobić stosując narzędzia dostępne w &lt;i&gt;MeeGo SDK&lt;/i&gt;:&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;mad -t meego-netbook-ia32-1.1.2 pscreate -t qt-simple qthello&lt;/pre&gt;&lt;br /&gt;
Przechodzimy do katalogu z projektem i uruchamiamy kompilację:&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;cd qthello
mad -t meego-netbook-ia32-1.1.2 qmake
mad -t meego-netbook-ia32-1.1.2 make&lt;/pre&gt;&lt;br /&gt;
Sprawdzamy czy plik wykonywalny istnieje:&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;file build/qthello&lt;/pre&gt;&lt;br /&gt;
Aplikację również możemy uruchomić wydając polecenie: &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;build/qthello&lt;/span&gt;. Powinno nam się pojawić okienko programu z widocznym przyciskiem „&lt;i&gt;Hello world&lt;/i&gt;”. Okienko należy wyłączyć zamykając program w konsoli ponieważ nie zawiera ono paska tytułowego z przyciskami sterującymi (zamknij, minimalizuj, itp.).&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;Instalacja i testowanie środowiska uruchomieniowego (&lt;i&gt;Runtime&lt;/i&gt;)&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Środowisko wdrożeniowe to za mało, aby wygodnie pisać i testować programy napisane dla &lt;i&gt;MeeGo&lt;/i&gt;. Potrzebne nam jest również środowisko uruchomieniowe (ang. &lt;i&gt;MeeGo Runtime&lt;/i&gt;), na którym będziemy mogli przetestować na żywo jak się sprawuje nasza aplikacja. Najlepiej jakbyśmy dysponowali jakimś urządzeniem, na którym jest zainstalowany &lt;i&gt;MeeGo&lt;/i&gt;. Jeśli jednak takim nie dysponujemy możemy skorzystać z testowego środowiska przygotowanego przez twórców &lt;i&gt;MeeGo&lt;/i&gt; w postaci maszyn wirtualnych &lt;i&gt;QEMU&lt;/i&gt;. Oczywiście do ich działania wymagana jest sprzętowa akceleracja wirtualizacji wbudowana w procesor. W sumie nie jest to wymóg samego &lt;i&gt;MeeGo&lt;/i&gt;, a jedynie &lt;i&gt;QEMU&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
Instalacja środowiska uruchomieniowego jest dobrze opisana na &lt;i&gt;Wiki MeeGo&lt;/i&gt;, gdzie również polecam zajrzeć: &lt;a href="http://wiki.meego.com/SDK/Docs/1.1/Configuring_QEMU_runtimes"&gt;http://wiki.meego.com/SDK/Docs/1.1/Configuring_QEMU_runtimes&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Aby sprawdzić jakie środowiska mamy do dyspozycji wydajemy polecenie:&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;mad-admin list runtimes&lt;/pre&gt;&lt;br /&gt;
Ja zainstalowałem na początek dwa z nich (uwaga: każde zajmuje ok. 650MB!):&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;sudo mad-admin create -f -e meego-netbook-ia32-qemu-1.1.2-runtime
sudo mad-admin create -f -e meego-handset-ia32-qemu-1.1.2-runtime&lt;/pre&gt;&lt;br /&gt;
Po instalacji możemy już przetestować na własnym komputerze czy to naprawdę działa:&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;sudo mad remote -r meego-netbook-ia32-qemu-1.1.2-runtime poweron
sudo mad remote -r meego-handset-ia32-qemu-1.1.2-runtime poweron&lt;/pre&gt;&lt;br /&gt;
Po zakończonych testach wyłączamy wirtualną maszynę poleceniem:&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;sudo mad remote -r meego-netbook-ia32-qemu-1.1.2-runtime poweroff
sudo mad remote -r meego-handset-ia32-qemu-1.1.2-runtime poweroff&lt;/pre&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: large;"&gt;Napotkane problemy&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Niestety przy podczas pierwszej próby włączenia dowolnego środowiska dostawałem komunikat:&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;Starting QEMU runtime meego-handset-ia32-w32-qemu-1.1.20101031.2201-sda-runtime
This may take some time ...&lt;/pre&gt;i nic się więcej nie działa. Nic nie startuje. Nic nie zjada zasobów procesora. Wyszło na to, że mój procesor (&lt;i&gt;AMD Phenom™ II X4 925&lt;/i&gt;) ma jakieś problemy ze wspomaganiem wirtualizacji sprzętowej. Jest też odpowiedni wpis na &lt;i&gt;Wiki Meego&lt;/i&gt;, który dotyczy tego problemu i tam polecam najpierw zajrzeć: &lt;a href="http://wiki.meego.com/SDK/Docs/1.1/MeeGo_SDK_Graphics_Acceleration"&gt;http://wiki.meego.com/SDK/Docs/1.1/MeeGo_SDK_Graphics_Acceleration&lt;/a&gt;. U mnie problem rozwiązał się po instalacji następujących pakietów:&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;sudo apt-get install qemu-kvm kvm&lt;/pre&gt;wydaniu polecenia:&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;sudo modprobe kvm_amd&lt;/pre&gt;i restarcie komputera. Później już wszystko ruszyło z miejsca :)&lt;/li&gt;
&lt;li&gt;Na innym komputerze, co do którego miałem pewność, że procesor, który się w nim znajduje (&lt;i&gt;Intel i3 530&lt;/i&gt;) powinien sobie poradzić był taki sam problem ze uruchomieniem środowiska &lt;i&gt;Runtime&lt;/i&gt;. Rozwiązanie było podobne jak poprzednio. Tutaj wystarczyło jedynie wpisać:&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;sudo modprobe kvm_intel&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;Niestety na komputerze z &lt;i&gt;AMD&lt;/i&gt; nie udało mi się uruchomić, żadnego środowiska uruchomieniowego dla telefonów. Domyślam się, że może to być związane z tym, że mam na nim kartę i sterowniki &lt;i&gt;NVidi&lt;/i&gt;. Na komputerze z Intelem wszystko było OK.&lt;/li&gt;
&lt;/ul&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Podsumowanie i zrzuty ekranu&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Na koniec jeszcze dwa przykładowe zrzuty ekranu jak to wygląda na żywo.&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="https://lh5.googleusercontent.com/_AeFiJN9phoM/TV6yg5QXFXI/AAAAAAAAFzQ/T3YiUgSFbe8/MeeGoo_netbook_sdk1.1.2_1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="https://lh5.googleusercontent.com/_AeFiJN9phoM/TV6yg5QXFXI/AAAAAAAAFzQ/T3YiUgSFbe8/MeeGoo_netbook_sdk1.1.2_1.png" width="500" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;i&gt;Środowisko dla netbooków&lt;/i&gt;&lt;/div&gt;&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="https://lh5.googleusercontent.com/_AeFiJN9phoM/TV6yYENGaCI/AAAAAAAAFy0/EbdjOPSeoVU/MeeGoo_handset_sdk1.1.2_1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="https://lh5.googleusercontent.com/_AeFiJN9phoM/TV6yYENGaCI/AAAAAAAAFy0/EbdjOPSeoVU/MeeGoo_handset_sdk1.1.2_1.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;i&gt;Środowisko dla telefonów&lt;/i&gt;&lt;/div&gt;&lt;br /&gt;
Więcej zrzutów można obejrzeć na poniższym pokazie slajdów:&lt;br /&gt;
&lt;div style="text-align: center;"&gt;&lt;div style="font-family: arial,sans-serif; font-size: 13px; width: 600px;"&gt;&lt;div&gt;&lt;embed flashvars="host=picasaweb.google.com&amp;amp;noautoplay=1&amp;amp;hl=pl&amp;amp;feat=flashalbum&amp;amp;RGB=0x000000&amp;amp;feed=https%3A%2F%2Fpicasaweb.google.com%2Fdata%2Ffeed%2Fapi%2Fuser%2Frpetryniak%2Falbumid%2F5575089303272666065%3Falt%3Drss%26kind%3Dphoto%26hl%3Dpl" height="400" pluginspage="http://www.macromedia.com/go/getflashplayer" src="https://picasaweb.google.com/s/c/bin/slideshow.swf" type="application/x-shockwave-flash" width="600"&gt;&lt;/embed&gt;&lt;/div&gt;&lt;span style="float: left;"&gt;&lt;a href="https://picasaweb.google.com/rpetryniak/MeeGooSystem?feat=flashalbum" style="color: #3964c2;"&gt;Wyświetl wszystkie&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div style="text-align: right;"&gt;&lt;a href="http://picasaweb.google.com/lh/getEmbed?feat=flashalbum" style="color: #3964c2;"&gt;Uzyskaj własny&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;
Pomimo tego, że środowisko dla netbooków, wygląda tak jak wielu czytelników zapewne widziało na różnych screenach w Internecie to nie można powiedzieć już tego samego o wersji na telefony. Jest ona bardzo okrojona, zawiera jedynie kilka dodatkowych aplikacji i w ogóle nie prezentuje się najlepiej. Ale przecież, nie jest to środowisko do codziennego używania, a jedynie do testów i rozwoju własnych aplikacji.&lt;br /&gt;
&lt;br /&gt;
Na razie to tyle :) Kolejnym razem opiszę jak do tego wszystkiego podłączyć &lt;i&gt;Qt Creatora&lt;/i&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19722740-5936590133404530293?l=rpetryniak.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://rpetryniak.blogspot.com/feeds/5936590133404530293/comments/default" title="Komentarze do posta" /><link rel="replies" type="text/html" href="http://rpetryniak.blogspot.com/2011/02/meego-pierwsze-starcie.html#comment-form" title="Komentarze (0)" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/19722740/posts/default/5936590133404530293?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/19722740/posts/default/5936590133404530293?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RafalPetryniakBlog/~3/PD3DkbzOY44/meego-pierwsze-starcie.html" title="MeeGo - pierwsze starcie" /><author><name>Rafał Petryniak</name><uri>https://profiles.google.com/106420849521837640393</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-ueopwOVHATs/AAAAAAAAAAI/AAAAAAAAGaw/TSrE-0eH8Zc/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://lh5.googleusercontent.com/_AeFiJN9phoM/TV6yg5QXFXI/AAAAAAAAFzQ/T3YiUgSFbe8/s72-c/MeeGoo_netbook_sdk1.1.2_1.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://rpetryniak.blogspot.com/2011/02/meego-pierwsze-starcie.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkECQXk5fCp7ImA9Wx9REU0.&quot;"><id>tag:blogger.com,1999:blog-19722740.post-3671342778230459838</id><published>2010-12-11T23:58:00.001+01:00</published><updated>2010-12-12T00:04:20.724+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-12-12T00:04:20.724+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="linux" /><category scheme="http://www.blogger.com/atom/ns#" term="kde" /><title>Kompilacja KDE ze źródeł dla niewtajemniczonych</title><content type="html">Kilka dni temu postanowiłem zmierzyć się z wyzwaniem samodzielnej kompilacji &lt;i&gt;KDE&lt;/i&gt; ze źródeł. To co po pierwszych próbach wydawało mi się niemal niemożliwe, ostatecznie okazało się nie tak skomplikowane jak sądziłem. Podstawowy błąd jaki robiłem na początku był taki, że kompilację uruchamiałem na starszym wydaniu &lt;i&gt;Kubuntu 10.04&lt;/i&gt;. Jest to wersja o dłuższym okresie serwisowania (tzw. &lt;i&gt;LTS&lt;/i&gt; - &lt;i&gt;Long Term Support&lt;/i&gt;), więc byłem przekonany, że programiści &lt;i&gt;KDE&lt;/i&gt; będą ją również wspierać w procesie kompilacji. Tak poza tym, to właśnie tą wersję miałem zainstalowaną na komputerze stacjonarnym i to był główny powód, dlaczego z niej skorzystałem. O problemach jakie wtedy napotkałem nie będę pisał, bo nie występowały one już w &lt;b&gt;Kubuntu 10.10&lt;/b&gt;. Tutaj jedynym problemem było zainstalowanie wszystkich wymaganych zależności na potrzeby kompilacji.&lt;br /&gt;
&lt;br /&gt;
Poniższy opis/poradnik powstał przy znacznym wykorzystaniu następujących materiałów dostępnych w Internecie:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;KDE TechBase: &lt;i&gt;&lt;a href="http://techbase.kde.org/Build_KDE4.6_on_Kubuntu"&gt;Build KDE4.6 on Kubuntu&lt;/a&gt;&lt;/i&gt; (opis kompilacji &lt;i&gt;KDE 4.6&lt;/i&gt; w &lt;i&gt;Kubuntu 10.04&lt;/i&gt;)&lt;/li&gt;
&lt;li&gt;KDE TechBase: &lt;i&gt;&lt;a href="http://techbase.kde.org/Getting_Started/Build/KDE4"&gt;Getting Started/Build/KDE4&lt;/a&gt;&lt;/i&gt; (oficjalna dokumentacja kompilacji &lt;i&gt;KDE&lt;/i&gt;)&lt;/li&gt;
&lt;li&gt;Blog: Who Says Penguins Can't Fly?: &lt;i&gt;&lt;a href="http://hanschen.org/2010/01/20/building-kde-sc-from-svn/"&gt;Building KDE SC from SVN&lt;/a&gt;&lt;/i&gt;.&lt;/li&gt;
&lt;/ul&gt;Warto do nich zajrzeć w razie pojawienia się innych niż opisane w tym  tekście problemów, lub jeśli będzie potrzeba bardziej dokładnego  doczytania się co skąd się bierze, bo ja nie zawsze dokładnie to  przedstawiam. &lt;br /&gt;
&lt;ul&gt;&lt;/ul&gt;&lt;span style="font-size: large;"&gt;Aktualizacja oprogramowania&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;Kubuntu&lt;/i&gt; w podstawowej konfiguracji zawiera jedynie wpisy do przetestowanych repozytoriów, co do których w miarę jest pewność, że pakiety tam zawarte będą działać stabilnie. Nie ma dodanych tych, które zawierają rozwojowe i testowe wersje pakietów. One właśnie są potrzebne w momencie kompilacji &lt;i&gt;KDE&lt;/i&gt;. Dodajemy zatem te repozytoria i instalujemy aktualizacje:&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;sudo add-apt-repository ppa:kubuntu-ppa/backports
sudo add-apt-repository ppa:kubuntu-ppa/beta
sudo apt-get update
sudo apt-get upgrade&lt;/pre&gt;&lt;br /&gt;
Nie wiem dlaczego, ale po wykonaniu tych kroków narzędzie do aktualizacji z &lt;i&gt;Kubuntu&lt;/i&gt; poinformowało mnie (trzeba sprawdzić odpowiednią ikonkę w zasobniku systemowym koło zegara), że jeszcze nie wszystkie zostały zainstalowane. Instalujemy wszystkie aktualizacje, które zostały zaproponowane.&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: large;"&gt;Instalujemy dodatkowe pakiety&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Tak jak wspomniałem na początku tego wpisu, na potrzeby kompilacji wymagane jest zainstalowanie wielu dodatkowych pakietów. Poniższa lista została opracowana na podstawie oficjalnej dokumentacji kompilacji &lt;i&gt;KDE&lt;/i&gt; pod &lt;i&gt;Debiana&lt;/i&gt; i &lt;i&gt;Ubuntu&lt;/i&gt;/&lt;i&gt;Kubuntu&lt;/i&gt;: &lt;a href="http://techbase.kde.org/Getting_Started/Build/KDE4/Kubuntu_and_Debian"&gt;http://techbase.kde.org/Getting_Started/Build/KDE4/Kubuntu_and_Debian&lt;/a&gt; oraz na podstawie własnych doświadczeń zebranych podczas kilku prób kompilacji &lt;i&gt;KDE&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;sudo apt-get install subversion git-core gcc g++

sudo apt-get install build-essential xorg-dev cdbs debhelper cmake kdesdk-scripts subversion ssh xserver-xephyr doxygen dbus-x11 libxml2-dev libxslt1-dev shared-mime-info libical-dev libgif-dev libssl-dev libboost-dev libboost-program-options-dev libboost-graph-dev libgpgme11-dev libxine-dev libqimageblitz-dev libbz2-dev libdbus-1-dev libpam0g-dev libpcre3-dev libkrb5-dev libsm-dev libclucene0ldbl libclucene-dev libjpeg62-dev libxtst-dev xsltproc libxrender-dev libfontconfig1-dev automoc librdf0-dev libdbusmenu-qt-dev docbook-xsl docbook-xml libattica-dev libqt4-webkit-dev shared-desktop-ontologies libphonon-dev

sudo apt-get install graphviz libqt4-dev libstreamanalyzer-dev libstrigiqtdbusclient-dev libxml2-utils libopenexr-dev libjasper-dev libenchant-dev libavahi-common-dev libaspell-dev libasound2-dev libldap2-dev libsasl2-dev libsmbclient-dev libxkbfile-dev libxcb1-dev libxklavier-dev libxdamage-dev libxcomposite-dev libbluetooth-dev libusb-dev network-manager-dev libsmbclient-dev libsensors-dev libnm-util-dev libusb-dev libcfitsio3-dev libnova-dev libeigen2-dev libopenbabel-dev libfacile-ocaml-dev libboost-python-dev libsvn-dev libsvncpp-dev libqt4-dev libqca2-dev libstreamanalyzer-dev libstrigiqtdbusclient-dev libcommoncpp2-dev libidn11 libidn11-dev libpci-dev libxss-dev libxft-dev libpoppler-qt4-dev libpolkit-agent-1-dev libpolkit-backend-1-dev libpolkit-qt-1-dev libspectre-dev

sudo apt-get install kdesdk kdelibs5-dev kdebase-workspace-dev libakonadi-dev libsoprano-dev libkonq5-dev libv4l-dev

sudo apt-get install flex bison libacl1-dev hspell&lt;/pre&gt;&lt;br /&gt;
&lt;span style="font-size: large;"&gt;Utworzenie nowego użytkownika&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Przed przystąpieniem do właściwego procesu kompilacji &lt;i&gt;KDE&lt;/i&gt;, warto zadać sobie pytanie: w jaki sposób chcemy mieć dostęp zarówno do nowego środowiska pracy jak również do wersji stabilnej, której używaliśmy do tej pory? W Internecie można znaleźć wiele odpowiedzi na to pytanie, m.in.: skorzystanie z środowiska wirtualnego (np. &lt;i&gt;VirtualBox&lt;/i&gt;) lub przełączanie głównej gałęzi struktury plików przy użyciu &lt;i&gt;chroot&lt;/i&gt;. W tym poradniku zostanie opisane jeszcze inne podejście, które jest zalecane w oficjalnej dokumentacji &lt;i&gt;KDE&lt;/i&gt;. Zostanie utworzony nowy użytkownik, na koncie którego zostanie przeprowadzona kompilacja i lokalna instalacja &lt;i&gt;KDE&lt;/i&gt;. "Lokalna" w tym wypadku oznacza, że tylko ten użytkownik będzie mógł korzystać z tej wersji &lt;i&gt;KDE&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
Tworzymy nowego użytkownika i dodajemy go do grup. Jeśli chcemy, aby użytkownik miał dostęp do trybu poleceń administratora (&lt;i&gt;sudo&lt;/i&gt;) zamiast do grupy &lt;i&gt;users&lt;/i&gt; dodajemy go do grupy &lt;i&gt;admin&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;sudo useradd -m -G users,audio,video,cdrom,plugdev -s /bin/bash kde-devel
sudo passwd kde-devel&lt;/pre&gt;&lt;br /&gt;
Logujemy się na konto właśnie utworzonego użytkownika:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;su - kde-devel&lt;/pre&gt;&lt;br /&gt;
&lt;span style="font-size: large;"&gt;Konfiguracja skryptów startowych&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Oficjalna dokumentacja zaleca, aby zaraz po zalogowaniu skonfigurować skrypty startowe w celu usprawnienia procesu kompilacji. Można to zrobić wykonując następujące czynności:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Robimy kopię zapasową oryginalnego pliku &lt;i&gt;.bashrc&lt;/i&gt;:&lt;pre class="prettyprint lang-bsh notranslate"&gt;cp .bashrc .bashrc_backup&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;Ze strony  &lt;a href="http://techbase.kde.org/Getting_Started/Increased_Productivity_in_KDE4_with_Scripts/.bashrc"&gt;http://techbase.kde.org/Getting_Started/Increased_Productivity_in_KDE4_with_Scripts/.bashrc&lt;/a&gt;  kopiujemy zawartość przykładowego pliku &lt;i&gt;.bashrc&lt;/i&gt; i wklejamy go do pliku  &lt;i&gt;.bashrc_KDE&lt;/i&gt;:&lt;pre class="prettyprint lang-bsh notranslate"&gt;nano .bashrc_KDE&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;Dodajemy do oryginalnego pliku &lt;i&gt;.bashrc&lt;/i&gt; ładowanie pliku &lt;i&gt;.bashrc_KDE&lt;/i&gt;:&lt;pre class="prettyprint lang-bsh notranslate"&gt;echo "source ~/.bashrc_KDE" &amp;gt;&amp;gt; ~/.bashrc&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;Wczytujemy ponownie zawartość pliku &lt;i&gt;.bashrc&lt;/i&gt;, aby jego zawartość była widoczna również dla bieżącej sesji:&lt;pre class="prettyprint lang-bsh notranslate"&gt;source ~/.bashrc&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;span style="font-size: large;"&gt;Konfiguracja narzędzia ''kdesrc-build''&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Na potrzeby kompilacji &lt;i&gt;KDE&lt;/i&gt; najłatwiej skorzystać ze skryptu &lt;b&gt;kdesrc-build&lt;/b&gt;, który można pobrać ze strony: &lt;a href="http://kdesvn-build.kde.org/"&gt;http://kdesvn-build.kde.org/&lt;/a&gt;. Skrypt ten automatyzuje wiele zadań, takich jak pobieranie źródeł, przygotowanie i uruchamianie procesu kompilacji.&lt;br /&gt;
&lt;br /&gt;
Pobranie i konfigurację skryptu &lt;i&gt;kdesrc-build&lt;/i&gt; wykonujemy za pomocą poniższych poleceń (na stronie projektu warto najpierw sprawdzić, czy nie ma nowszej wersji tego narzędzia):&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;mkdir -p ~/kdesrc/kdesrc-build
wget http://kdesvn-build.kde.org/releases/kdesrc-build-1.12.tar.bz2
tar xjvf kdesrc-build-1.12.tar.bz2 -C ~/kdesrc/kdesrc-build/
rm kdesrc-build-1.12.tar.bz2
cp ~/kdesrc/kdesrc-build/kdesrc-build-1.12/kdesrc-buildrc-sample ~/.kdesrc-buildrc&lt;/pre&gt;&lt;br /&gt;
Uruchomienie procesu kompilacji:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;~/kdesrc/kdesrc-build/kdesrc-build-1.12/kdesrc-build&lt;/pre&gt;&lt;br /&gt;
Domyślnie proces kompilacji jest uruchamiany w trybie zrównoleglonym (opcja &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;-j&lt;/span&gt; programu &lt;i&gt;make&lt;/i&gt;) w 2 procesach. Warto jednak pamiętać, że:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;jeśli mamy 1 jeden rdzeń obliczeniowy to nie przyniesie to żadnego efektu;&lt;/li&gt;
&lt;li&gt;w przypadku większej liczby rdzeni warto z nich skorzystać i uruchomić proces kompilacji z odpowiednio ustawionym parametrem &lt;i&gt;make-options&lt;/i&gt; skryptu &lt;i&gt;kdesrc-build&lt;/i&gt;. Przykład dla 4 procesorów:&lt;/li&gt;
&lt;/ul&gt;&lt;pre class="prettyprint lang-bsh notranslate"&gt;~/kdesrc/kdesrc-build/kdesrc-build-1.12/kdesrc-build --make-options=-j4&lt;/pre&gt;&lt;br /&gt;
&lt;span style="font-size: large;"&gt;Problemy&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Podczas kompilacji pojawił mi się następujący komunikat o błędzie:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;Building phonon-git (3/15)
  Waiting for source code update.
  Source update complete for phonon-git: 0 files affected.
  Compiling...
  Build succeeded after 1 second.
  Installing phonon-git.
  Unable to install phonon-git!
  Overall time for phonon-git was 1 second.&lt;/pre&gt;&lt;br /&gt;
Warto podejrzeć co znajduje się w logach. U mnie odpowiedni plik znajdował się w następującej lokalizacji:&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;cat ~/kdesvn/log/2010-12-05-03/phonon-git/install.log&lt;/pre&gt;&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;CMake Error at cmake_install.cmake:40 (FILE):
  file INSTALL cannot copy file
  "/home/kde-devel/kdesvn/phonon-git/qt_phonon.pri" to
  "/usr/share/qt4/mkspecs/modules/qt_phonon.pri".&lt;/pre&gt;&lt;br /&gt;
Wynika z niego, że pomimo przyjętych założeń o lokalnej instalacji &lt;i&gt;KDE&lt;/i&gt; na koncie użytkownika &lt;i&gt;kde-devel&lt;/i&gt;, instalator &lt;i&gt;Photona&lt;/i&gt; próbuje umieścić coś w głównej strukturze plików. Można to wyłączyć edytując następujący plik:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;nano kdesvn/phonon-git/CMakeLists.txt&lt;/pre&gt;&lt;br /&gt;
i umieszczając w komentarzu tą linię (znajduje się ona na końcu pliku):&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;#install(FILES qt_phonon.pri DESTINATION  ${QT_MKSPECS_DIR}/modules)&lt;/pre&gt;&lt;br /&gt;
&lt;u&gt;Uwaga&lt;/u&gt;: Oczywiście nie mam pewności, czy to jest najlepsze z możliwych rozwiązań i czy później nie wpłynie to na błędy podczas używania nowego &lt;i&gt;KDE&lt;/i&gt;. Najważniejsze jest jednak to, że kompilacja idzie dalej :-)&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: large;"&gt;Kompilujemy dodatkowe programy&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Skrypt &lt;i&gt;kdesrc-build&lt;/i&gt; poza domyślnym zestawem modułów, które mogliśmy zobaczyć podczas jego działania, obsługuje jeszcze kilka, które domyślnie są wyłączone. Aby je włączyć do procesu kompilacji, należy wedytować poniższej wskazany plik i odkomentować potrzebne nam moduły:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;nano ~/.kdesrc-buildrc&lt;/pre&gt;&lt;br /&gt;
Zauważyłem jednak, że pewne moduły, które są tutaj umieszczone nie działają. Przykładem jest zestaw narzędzi developerskich &lt;i&gt;KDE&lt;/i&gt;: &lt;b&gt;kdevplatform&lt;/b&gt;, &lt;b&gt;kdevelop&lt;/b&gt;, &lt;b&gt;quanta&lt;/b&gt;. Problem z ich kompilacją wynika stąd, że ich kod nie jest dłużej dostępny w repozytorium &lt;i&gt;subversion&lt;/i&gt; i został przeniesiony do repozytorium &lt;i&gt;git&lt;/i&gt;. Mi osobiście zależało na tym, aby mieć te moduły skompilowane, dlatego poniżej znajduje się opis, jak można to zrobić samodzielnie.&lt;br /&gt;
&lt;br /&gt;
Zakładamy katalog, w którym będziemy umieszczać dodatkowe programy &lt;i&gt;KDE&lt;/i&gt;, które będziemy samodzielnie kompilować:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;mkdir kdesoftware
cd kdesoftware&lt;/pre&gt;&lt;br /&gt;
Pobieramy źródła programów związanych z &lt;i&gt;KDevelopem&lt;/i&gt;:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;git clone git://gitorious.org/kdevelop/kdevplatform.git
git clone git://gitorious.org/kdevelop/kdevelop.git
git clone git://gitorious.org/kdevelop/quanta.git&lt;/pre&gt;&lt;br /&gt;
Tworzymy katalogi budowania:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;mkdir -p build/{kdevplatform,kdevelop,quanta}&lt;/pre&gt;&lt;br /&gt;
Uruchamiamy procedurę kompilacji i instalacji:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;cd ~/kdesoftware/build/kdevplatform/
cmake -DCMAKE_INSTALL_PREFIX=~/kde/ ../../kdevplatform/
make &amp;amp;&amp;amp; make install

cd ~/kdesoftware/build/kdevelop/
cmake -DCMAKE_INSTALL_PREFIX=~/kde/ ../../kdevelop/
make &amp;amp;&amp;amp; make install

cd ~/kdesoftware/build/quanta/
cmake -DCMAKE_INSTALL_PREFIX=~/kde/ ../../quanta/
make &amp;amp;&amp;amp; make install&lt;/pre&gt;&lt;br /&gt;
&lt;span style="font-size: large;"&gt;Testowanie nowego KDE&lt;/span&gt;&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Jeśli chcemy przetestować pojedynczy program z właśnie skompilowanego  &lt;i&gt;KDE&lt;/i&gt;, a zarazem nie chcemy uruchamiać całego środowiska,  najlepiej skorzystać z narzędzia &lt;i&gt;sux&lt;/i&gt;:&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;sudo apt-get install sux
sux - kde-devel
dolphin&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;Aby przetestować działanie pełnego środowiska &lt;i&gt;KDE&lt;/i&gt; wystarczy zalogować się na użytkownika &lt;i&gt;kde-devel&lt;/i&gt; wybierając jako typ sesji na „&lt;i&gt;Bezpieczne logowanie&lt;/i&gt;” i uruchomić program:&lt;pre class="prettyprint lang-bsh notranslate"&gt;~/kde/bin/startkde&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&amp;nbsp;Jeśli chcielibyśmy to zrobić „bardziej elegancko” najlepszym  rozwiązaniem wydaje się przygotowanie nowego typu sesji, którą będziemy  mogli wybrać podczas logowania. Należy w tym celu wykonać następujące  operacje (jako użytkownik z prawami administracyjnymi):&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;cd /usr/share/kde4/apps/kdm/sessions/
sudo cp kde-plasma.desktop kde-plasma-trunk.desktop
sudo nano kde-plasma-trunk.desktop&lt;/pre&gt;&lt;br /&gt;
Do pliku &lt;i&gt;kde-plasma-trunk.desktop&lt;/i&gt; wklejamy poniższą zawartość:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;[Desktop Entry]
Encoding=UTF-8
Type=XSession
Exec=/home/kde-devel/kde/bin/startkde
TryExec=/home/kde-devel/kde/bin/startkde
Name=KDE Trunk           
Comment=The desktop made by KDE&lt;/pre&gt;&lt;br /&gt;
Teraz już podczas logowania zamiast tradycyjnej sesji KDE, wybieramy z listy sesję &lt;i&gt;KDE Trunk&lt;/i&gt;.&lt;br /&gt;
&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
&lt;span style="font-size: large;"&gt;Podsumowanie&lt;/span&gt;&lt;br /&gt;
Powyższy opis tak jak tytuł wskazuje, został przygotowany dla użytkowników początkujących lub średnio obeznanych z administracją i programowaniem w &lt;i&gt;Linuksie&lt;/i&gt;. Domyślam się, że zaawansowani użytkownicy &lt;i&gt;KDE&lt;/i&gt; znaleźli by tu kilka błędów, lub przedstawili bardziej zoptymalizowany proces kompilacji. Dla mnie najważniejszym jednak jest to, że kompilację udało mi się nie tylko rozpocząć, ale również zakończyć :-), co pozwala mi się czuć bardziej wtajemniczonym w obsługę tego systemu, aniżeli jeszcze kilkanaście dni temu.&lt;br /&gt;
&lt;br /&gt;
Zachęcam do zadawania pytań lub do wpisywania komentarzy, co można poprawić w powyższym poradniku. W razie problemów  poszukiwanie odpowiedzi najlepiej zacząć od oficjalnej dokumentacji na stronie: &lt;a href="http://techbase.kde.org/Getting_Started/Build/KDE4/Troubleshooting"&gt;http://techbase.kde.org/Getting_Started/Build/KDE4/Troubleshooting&lt;/a&gt;. Zostały tam opisane  najczęstsze problemy i ich rozwiązania.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19722740-3671342778230459838?l=rpetryniak.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://rpetryniak.blogspot.com/feeds/3671342778230459838/comments/default" title="Komentarze do posta" /><link rel="replies" type="text/html" href="http://rpetryniak.blogspot.com/2010/12/kompilacja-kde-ze-zrode-dla.html#comment-form" title="Komentarze (4)" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/19722740/posts/default/3671342778230459838?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/19722740/posts/default/3671342778230459838?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RafalPetryniakBlog/~3/QRTRQnM4U-A/kompilacja-kde-ze-zrode-dla.html" title="Kompilacja KDE ze źródeł dla niewtajemniczonych" /><author><name>Rafał Petryniak</name><uri>https://profiles.google.com/106420849521837640393</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-ueopwOVHATs/AAAAAAAAAAI/AAAAAAAAGaw/TSrE-0eH8Zc/s512-c/photo.jpg" /></author><thr:total>4</thr:total><feedburner:origLink>http://rpetryniak.blogspot.com/2010/12/kompilacja-kde-ze-zrode-dla.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A08CRHg_cSp7ImA9Wx9TEEs.&quot;"><id>tag:blogger.com,1999:blog-19722740.post-5810941635683673951</id><published>2010-11-18T01:14:00.003+01:00</published><updated>2010-11-18T09:44:25.649+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-11-18T09:44:25.649+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="linux" /><title>Wygodna integracja Windows7 z Ubuntu za pomocą VirtualBoxa</title><content type="html">Pisałem ostatnio o &lt;a href="http://rpetryniak.blogspot.com/2010/11/konfiguracja-lokalnego-serwera-pakietow.html"&gt;konfiguracji lokalnego repozytorium pakietów&lt;/a&gt; na potrzeby sal dydaktycznych, którymi się opiekuję na &lt;i&gt;Politechnice Krakowskiej&lt;/i&gt;. Na salach tych, o których mowa nie będzie zainstalowany jedynie &lt;i&gt;Ubuntu&lt;/i&gt;, ale również &lt;i&gt;Windows7&lt;/i&gt;. Aby ułatwić sobie dalszą pracę w zarządzaniu tym systemem, postanowiłem zainstalować go w maszynie wirtualnej stosując &lt;a href="http://www.virtualbox.org/"&gt;&lt;i&gt;VirtualBoxa&lt;/i&gt;&lt;/a&gt;. Jest wiele innych narzędzi do wirtualizacji, jednakże po lekturze różnych porównań w Internecie przekonałem się właśnie do wyboru narzędzia firmowanego logo &lt;i&gt;Oracle&lt;/i&gt;. Oczywiście poza moją wygodą w administracji obu systemami na raz, najważniejsza jest wygoda i prostota obsługi przez potencjalnych użytkowników, którymi są studenci różnych kierunków &lt;i&gt;Wydziału Mechanicznego&lt;/i&gt;. Ilość osób, które przewija się przez te sale w 2 tygodniowym toku zajęć (tygodnie parzyste i nieparzyste) zdecydowanie przewyższa pół tysiąca osób. Fakt ten wymaga, aby na sali wszystko działało bez zarzutu.&lt;br /&gt;
&lt;br /&gt;
W tym poradniku chciałem przedstawić poszczególne kroki konfiguracji wirtualnej maszyny z &lt;i&gt;Windows7&lt;/i&gt; na potrzeby zajęć dydaktycznych. Na ile to będzie możliwe poszczególne czynności będą wykonywane za pomocą poleceń w konsoli, a nie za pomocą narzędzi graficznych.Takie podejście pozwala na pisanie skryptów, które potrafią znacznie ułatwić pracę w przypadku kiedy te same czynności należy wykonać kilka/kilkanaście razy. &lt;br /&gt;
&lt;br /&gt;
Jedną z najbardziej przydatnych, a niestety mało znanych funkcji &lt;i&gt;VirtualBoxa&lt;/i&gt;, która zostanie omówiona jest możliwość zmiany trybu pracy dysku i przełączenie go w stan resetu danych po każdym wyłączeniu maszyny wirtualnej.&lt;br /&gt;
&lt;br /&gt;
Mam nadzieje, że przedstawione porady okażą się również przydatne dla typowego użytkownika komputera, a nie tylko dla osoby przygotowującej sale na zajęcia lub szkolenia.&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: large;"&gt;Czynności wstępne&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Na początek gorąco polecam zapoznać się z oficjalną dokumentacją narzędzia &lt;i&gt;&lt;b&gt;VBoxManage&lt;/b&gt;&lt;/i&gt;, które pozwala na wykonanie tych samych (a nawet więcej) czynności co ogólnie znany interfejs graficzny &lt;i&gt;VirtualBoxa&lt;/i&gt; (&lt;a href="http://www.virtualbox.org/manual/ch08.html"&gt;strona dokumentacji tego narzędzia&lt;/a&gt;). Większość kroków w tym poradniku wykonanych jest za jego pomocą. Nie piszę jednak szczegółowych opisów dla poszczególnych poleceń, dlatego właśnie odsyłam do dokumentacji.&lt;br /&gt;
&lt;br /&gt;
Pierwszą czynnością administracyjną, którą polecam na początek jest przygotowanie dodatkowego użytkownika, którego możemy nazwać np. "&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;windows&lt;/span&gt;". Docelowo dla tego użytkownika zostanie ustawione, aby zaraz po zalogowaniu do systemu startowała wirtualna maszyna z &lt;i&gt;Windows7&lt;/i&gt;. Można oczywiście ten krok pominąć i skonfigurować sobie &lt;i&gt;VirtualBoxa&lt;/i&gt; do pracy na obecnie używanym koncie użytkownika. &lt;br /&gt;
&lt;br /&gt;
Dodać nowego uzytkownika w Ubuntu możemy wybierając odpowiednio w menu: &lt;i&gt;&amp;nbsp;&lt;/i&gt;&lt;br /&gt;
&lt;i&gt;System → Administracja → Użytkownicy i grupy → Dodaj&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: large;"&gt;Instalacja VirtualBox&lt;/span&gt;&lt;br /&gt;
Instalację &lt;i&gt;VirtualBoxa&lt;/i&gt; najlepiej przeprowadzać zgodnie z oficjalnym opisem zamieszczonym na stronie: &lt;a href="http://www.virtualbox.org/wiki/Linux_Downloads"&gt;http://www.virtualbox.org/wiki/Linux_Downloads&lt;/a&gt;. W &lt;i&gt;Ubuntu&lt;/i&gt; sprowadza się to do dodania odpowiedniego repozytorium, pobrania i dodania kluczy uwierzytelniających oraz instalacji następujących pakietów:&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;sudo apt-get install virtualbox-3.2 dkms&lt;/pre&gt;&lt;br /&gt;
&lt;span style="font-size: large;"&gt;Utworzenie wzorcowej maszyny wirtualnej&lt;/span&gt;&lt;br /&gt;
Przed stworzeniem pierwszej maszyny wirtualnej, która może być wzorcem do tworzenia kolejnych maszyn trzeba zalogować się na konto "&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;windows&lt;/span&gt;" i tam uruchomić &lt;i&gt;VirtualBoxa&lt;/i&gt;. Zaraz po zaakceptowaniu licencji można wyłączyć program. &lt;br /&gt;
&lt;br /&gt;
W tym momencie można jeszcze utworzyć katalog, który będzie współdzielony pomiędzy &lt;i&gt;Ubuntu&lt;/i&gt;, a &lt;i&gt;Windowsem&lt;/i&gt;:&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;mkdir /home/windows/share&lt;/pre&gt;&lt;br /&gt;
Tworzenie maszyny wirtualnej można wykonać w prosty sposób w konsoli. Takie podejście zostanie tutaj omówione. Osobom, które nie chcą szczegółowo wgłębiać się w poszczególne parametry i czytać dokumentację &lt;i&gt;VBoxManage&lt;/i&gt;, polecam jednak interfejs graficzny. Tam wygodny kreator poprowadzi nas za rękę i znaczną część pracy zrobi za nas w tle. Później dla przećwiczenia polecam przygotowanie odpowiednich poleceń konsoli, które zrobią dokładnie to samo, co wcześniej ustawiliśmy w narzędziu graficznym.&lt;br /&gt;
&lt;br /&gt;
Tworzenie wirtualnej maszyny dla &lt;i&gt;Windows7&lt;/i&gt; może składać się z następujących kroków:&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;Utworzenie i automatyczne zarejestrowanie wirtualnej maszyny dla 32-bitowego &lt;i&gt;Windows7&lt;/i&gt;:&lt;pre class="prettyprint lang-bsh notranslate"&gt;VBoxManage createvm --name Windows7_01 --ostype Windows7 --register&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;Szczegółowa konfiguracja parametrów wirtualnej maszyny (szczegóły można doczytać w &lt;a href="http://www.virtualbox.org/manual/ch08.html#vboxmanage-modifyvm"&gt;dokumentacji polecenia &lt;i&gt;modifyvm&lt;/i&gt;&lt;/a&gt;):&lt;pre class="prettyprint lang-bsh notranslate"&gt;VBoxManage modifyvm Windows7_01 --memory 1780 --vram 40 --accelerate3d on --accelerate2dvideo on --boot1 dvd --boot2 disk --boot3 none --cpus 2 --pae on --hwvirtex on --largepages on --ioapic on --clipboard bidirectional --usb on --usbehci on&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;Udostępnianie lokalnego katalogu dla zwirtualizowanego systemu:&lt;pre class="prettyprint lang-bsh notranslate"&gt;VBoxManage sharedfolder add Windows7_01 --name "share" --hostpath "/home/windows/share"&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;Utworzenie kontrolerów &lt;i&gt;IDE&lt;/i&gt; i &lt;i&gt;SATA&lt;/i&gt; dla nośników danych:&lt;pre class="prettyprint lang-bsh notranslate"&gt;VBoxManage storagectl Windows7_01 --name "Kontroler SATA" --add sata --hostiocache on --controller IntelAhci
VBoxManage storagectl Windows7_01 --name "Kontroler IDE" --add ide --hostiocache on --controller PIIX4&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;Utworzenie i podpięcie dysku twardego (dysk rozszerzalny o maksymalnym rozmiarze 60GB):&lt;pre class="prettyprint lang-bsh notranslate"&gt;VBoxManage createhd --filename /home/windows/.VirtualBox/HardDisks/Windows7_01.vdi --size 60000
VBoxManage storageattach Windows7_01 --storagectl "Kontroler SATA" --port 0 --device 0 --type hdd --medium /home/windows/.VirtualBox/HardDisks/Windows7_01.vdi&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;Podłączenie napędu &lt;i&gt;CD/DVD&lt;/i&gt; z włączoną funkcją zapisu (oczywiście ma to sens jeśli mamy nagrywarkę):&lt;pre class="prettyprint lang-bsh notranslate"&gt;VBoxManage storageattach Windows7_01 --storagectl "Kontroler IDE" --port 1 --device 1 --type dvddrive --medium host:/dev/sr0 --passthrough on&lt;/pre&gt;&lt;/li&gt;
&lt;/ol&gt;Tak przygotowana maszyna powinna być już widoczna i gotowa do uruchomienia z poziomu okienkowego interfejsu &lt;i&gt;VirtualBoxa&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: large;"&gt;Zarządzanie VirtuaBoxem z poziomu konsoli&lt;/span&gt;&lt;br /&gt;
Do innych czynności, które możemy wykonać w konsoli można zaliczyć:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;u&gt;Uruchamianie maszyny wirtualnej&lt;/u&gt;. Maszynę możemy uruchamiać na dwa sposoby:&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;VBoxManage startvm Windows7_01
VirtualBox -startvm Windows7_01&lt;/pre&gt;Generalnie skutek wykonania obu poleceń będzie ten sam. Jedyną różnicą jaką ja zauważyłem jest uruchomienie zadania w tle przez pierwsze polecenie, w odróżnieniu od drugiego polecenia, gdzie wiersz polecenia oczekuje na zamkniecie programu &lt;i&gt;VirtualBox&lt;/i&gt;. To drugie polecenie przyda się właśnie na etapie konfiguracji &lt;i&gt;GDM&lt;/i&gt; (opis w dalszej części poradnika).&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;&lt;u&gt;Rejestrowanie maszyny wirtualnej&lt;/u&gt;. Przydaje się szczególnie jeśli przekopiujemy maszynę na inny komputer i chcemy z niej korzystać.&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;VBoxManage registervm /home/windows/.VirtualBox/Machines/Windows7_01/Windows7_01.xml&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;u&gt;Wyrejestrowywanie&lt;/u&gt;. Jeśli maszyna nie będzie dłużej wykorzystywana na bierzącym komputerze, bo np. została przeniesiona na inny, warto ją usunąć z wewnętrznego rejestru maszyn wirtualnych &lt;i&gt;VirtualBoxa&lt;/i&gt;.&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;VBoxManage unregistervm Windows7_01&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;span style="font-size: large;"&gt;Tworzenie kopii maszyny wirtualnej&lt;/span&gt;&lt;br /&gt;
Kiedy mamy już przygotowaną wzorcową maszynę wirtualną z &lt;i&gt;Windows7&lt;/i&gt; i chcielibyśmy ją powielić na inne komputery, warto najpierw zmniejszyć rozmiar wirtualnego dysku. W tym celu należy wykonać dwie czynności:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Zerowanie pustych bloków na dysku w &lt;i&gt;Windows7&lt;/i&gt; (&lt;u&gt;uwaga&lt;/u&gt;: dysk musi być w trybie &lt;i&gt;normal&lt;/i&gt;, a nie &lt;i&gt;immutable&lt;/i&gt; - tryby te opisane są w dalszej części poradnika). Pomocne w tej czynności będzie małe narzędzie &lt;i&gt;&lt;b&gt;sdelete&lt;/b&gt;&lt;/i&gt;, które można pobrać ze strony &lt;i&gt;Technet Microsoft&lt;/i&gt; (&lt;a href="http://technet.microsoft.com/en-us/sysinternals/bb897443.aspx"&gt;link do narzędzia&lt;/a&gt;). W wierszu poleceń w systemie &lt;i&gt;Windows&lt;/i&gt; wpisujemy:&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;sdelete -c&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;Kompaktowanie dysku w &lt;i&gt;VirtualBox&lt;/i&gt;. Stosujemy polecenie:&lt;pre class="prettyprint lang-bsh notranslate"&gt;VBoxManage modifyhd /home/windows/.VirtualBox/HardDisks/Windows7_01.vdi --compact&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;Zabiegi te w moim wypadku pozwoliły na odchudzenie dysku wirtualnego z 9.4GB na 8.3GB. Ten 1GB potrafi zrobić różnicę podczas klonowania wielu dysków wirtualnych i ich późniejszego kopiowania na inne komputery.&lt;br /&gt;
&lt;br /&gt;
Kolejnym krokiem jest tzw. proces &lt;i&gt;klonowania dysku&lt;/i&gt;. Jest to nic innego jak jego kopiowanie z nadaniem mu unikalnego identyfikatora. &amp;nbsp; &lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;VBoxManage clonehd /home/windows/.VirtualBox/HardDisks/Windows7_01.vdi /home/windows/.VirtualBox/HardDisks/Windows7_02.vdi --format VDI&lt;/pre&gt;&lt;br /&gt;
Na sam koniec, kiedy przekopiujemy katalog z ustawieniami maszyny wirtualnej oraz dysk wirtualny na inny komputer warto się upewnić, że są ustawione odpowiednie prawa dostępu dla użytkownika &lt;i&gt;windows&lt;/i&gt;:&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;sudo chown windows -R /home/windows/.VirtualBox
sudo chgrp windows -R /home/windows/.VirtualBox&lt;/pre&gt;&lt;br /&gt;
&lt;span style="font-size: large;"&gt;Blokada dysków do zapisu&lt;/span&gt;&lt;br /&gt;
Dyski w &lt;i&gt;VirtualBoxie&lt;/i&gt; mogą pracować w różnych trybach zapisu (po szczegóły odsyłam do &lt;a href="http://www.virtualbox.org/manual/ch05.html#hdimagewrites"&gt;oficjalnej dokumentacji&lt;/a&gt;). Co ciekawe przełaczać się między tymi trybami można jedynie za pomocą narzędzia &lt;i&gt;VBoxManage&lt;/i&gt; - okienkowa wersja tego nie umożliwia. Mnie osobiście poza standardowym trybem &lt;i&gt;normal&lt;/i&gt;, zainteresował szczególnie tryb &lt;i&gt;immutable&lt;/i&gt;, który nie zezwala na zapisywanie trwałych zmian na wirtualnym dysku. Dzięki temu po każdych zajęciach ze studentami, system &lt;i&gt;Windows&lt;/i&gt; jest przywracany do pierwotnego, wzorcowego stanu. &lt;br /&gt;
&lt;br /&gt;
Technicznie działa to w ten sposób, że wszystkie zmiany jakie wprowadzi użytkownik podczas pracy w systemie zapisywane są na tak zwanym dysku różnicowym. Stan tego dysku jest resetowany po każdym wyłączeniu maszyny. W przypadku restartu maszyny stan nie jest kasowany, co ma zabezpieczać naszą tymczasową pracę na wypadek zawieszenia się systemu goszczącego (w tym wypadku &lt;i&gt;Windows7&lt;/i&gt;). &lt;br /&gt;
&lt;br /&gt;
Do przełączania między tymi dwoma stanami najwygodniej będzie przygotować osobne skrypty:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Przejście z trybu &lt;i&gt;&lt;b&gt;normal&lt;/b&gt;&lt;/i&gt; do &lt;i&gt;&lt;b&gt;immutable&lt;/b&gt;&lt;/i&gt;:&lt;pre class="prettyprint lang-bsh notranslate"&gt;#!/bin/bash

VBoxManage storageattach Windows7_01 --storagectl "Kontroler SATA" --port 0 --device 0 --type hdd --medium none
VBoxManage modifyhd /home/windows/.VirtualBox/HardDisks/Windows7_01.vdi settype immutable
VBoxManage storageattach Windows7_01 --storagectl "Kontroler SATA" --port 0 --device 0 --type hdd --medium /home/windows/.VirtualBox/HardDisks/Windows7_01.vdi

echo `date`" : convert normal to immutable" &amp;gt;&amp;gt; vm_log.txt&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;Przejście z trybu &lt;i&gt;&lt;b&gt;immutable&lt;/b&gt;&lt;/i&gt; do &lt;i&gt;&lt;b&gt;normal&lt;/b&gt;&lt;/i&gt;:&lt;pre class="prettyprint lang-bsh notranslate"&gt;#!/bin/bash

VBoxManage storageattach Windows7_01 --storagectl "Kontroler SATA" --port 0 --device 0 --type hdd --medium none
VBoxManage modifyhd /home/windows/.VirtualBox/HardDisks/Windows7_01.vdi settype normal

for file in `ls /home/windows/.VirtualBox/Machines/Windows7_01/Snapshots/*.vdi`
do
  VBoxManage closemedium disk $file --delete
done

VBoxManage storageattach Windows7_01 --storagectl "Kontroler SATA" --port 0 --device 0 --type hdd --medium /home/windows/.VirtualBox/HardDisks/Windows7_01.vdi

echo `date`" : convert immutable to normal" &amp;gt;&amp;gt; vm_log.txt&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;W obu skryptach pierwszą i ostatnia czynnością jest odpowiednio odłączenie i podłączenie dysku do wirtualnego kontrolera &lt;i&gt;SATA&lt;/i&gt;. W drugim skrypcie mamy dodatkowo odłączenie i skasowanie dysków różnicowych. Czynność ta zapewnia poprawną pracę w trybie &lt;i&gt;normal&lt;/i&gt; i umożliwia wprowadzania dalszych zmian na wzorcowych dyskach wirtualnych (np. doinstalowanie kolejnych programów niezbędnych do zajęć).&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: large;"&gt;Konfiguracja GDM&lt;/span&gt;&lt;br /&gt;
Do tej pory opisywane kroki należały raczej do standardowych czynności administracyjnych dotyczących zarządzania wirtualna maszyną &lt;i&gt;VirtualBox&lt;/i&gt;. Jakiejś szczególnej &lt;u&gt;wygody&lt;/u&gt;, o której jest mowa w tytule nie widać. Trzeba się zwyczajnie zalogować do systemu, uruchomić &lt;i&gt;VirtualBoxa&lt;/i&gt; i wystartować maszynę z &lt;i&gt;Windows7&lt;/i&gt;. Może nie jest to jakość szczególnie skomplikowane, ale każdorazowo wymaga wykonania kilku tych samych czynności. Aby to zmienić i nieco usprawnić uruchamianie &lt;i&gt;Windowsa&lt;/i&gt; można przygotować specjalną sesja dla menadżera logowania &lt;i&gt;GDM&lt;/i&gt;. Dzięki temu już podczas logowania użytkownik będzie mógł wybrać sesję z &lt;i&gt;VirtualBoxem&lt;/i&gt; i automatycznym startem maszyny wirtualnej.&lt;br /&gt;
&lt;br /&gt;
Na początek tworzymy i edytujemy skrypt &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;vm_start.bsh&lt;/span&gt; do uruchamiania maszyny wirtualnej:&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;#!/bin/bash
VirtualBox -startvm Windows7_01&lt;/pre&gt;&lt;br /&gt;
Później tworzymy nowy plik z ustawieniami dla sesji &lt;i&gt;GDM&lt;/i&gt;:&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;sudo touch /usr/share/xsessions/windows7.desktop
sudo nano /usr/share/xsessions/windows7.desktop&lt;/pre&gt;do którego wpisujemy takie ustawienia:&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;[Desktop Entry]
Encoding=UTF-8
Name=Windows7
Comment=Sesja skonfigurowana dla użytkownika "windows". Dla pozostałych nie działa.
Exec=/home/windows/.VirtualBox/vm_start.bsh
TryExec=/home/windows/.VirtualBox/vm_tools/vm_start.bsh
Icon=
Type=Application&lt;/pre&gt;Teraz wystarczy się już wylogować i zalogować ponownie wybierając z listy sesję "Windows7". Powininna wystartować sama maszyna wirtualna bez startu sesji środowiska &lt;i&gt;Gnome&lt;/i&gt;. Po wyłączeniu &lt;i&gt;Windows&lt;/i&gt; w maszynie wirtualnej zamknie nam się również &lt;i&gt;VirtualBox&lt;/i&gt; i zostaniemy automatycznie wylogowani z systemu.&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: large;"&gt;Logowanie bez podawania hasła&lt;/span&gt;&lt;br /&gt;
Aby jeszcze bardziej ułatwić dostęp do &lt;i&gt;Windowsa&lt;/i&gt; można wyłączyć konieczność podawania hasła przez użytkownika "&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;windows&lt;/span&gt;". W tym celu logujemy się na konto z uprawnieniami roota i zmieniamy ustawienia użytkownika "&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;windows&lt;/span&gt;" ustawiając opcję "&lt;i&gt;Bez pytania o hasło przy logowaniu&lt;/i&gt;". Dzięki temu przy kolejnym logowaniu nie będzie trzeba podawać hasła i od razu wystartuje maszyna wirtualna. Warto również zwrócić uwagę, że dla użytkownika "&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;windows&lt;/span&gt;" nie będzie już możliwości zmiany sesji na inną (nie pojawi się okienko wyboru sesji, tylko użytkownik od razu  zostanie zalogowany).&amp;nbsp; Jeśli zależało by nam jednak na tym, aby znowu z poziomu użytkownika "&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;windows&lt;/span&gt;" dostać do Gnome, w celu zmiany jakichś ustawień, to na powrót ustawiamy konieczość podawania hasła przez tego użytkownika. Można to również zrobić z linii komend poleceniem:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Logowanie bez podawania hasła:&lt;pre class="prettyprint lang-bsh notranslate"&gt;sudo usermod -a -G nopasswdlogin windows&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;Konieczność podawania hasła:&lt;pre class="prettyprint lang-bsh notranslate"&gt;sudo gpasswd -d windows nopasswdlogin &lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
&lt;span style="font-size: large;"&gt;Problemy i rozwiązania&lt;/span&gt;&lt;br /&gt;
Jedynym problemem jaki do tej pory spotkałem w korzystaniu z &lt;i&gt;VirtualBoxa&lt;/i&gt;, było okresowe blokowanie się klawiatury w maszynie goszczącej. Zauważyłem, że dzieje się to zawsze po dłuższym czasie braku aktywności na komputerze, kiedy włączy się wygaszać ekranu w &lt;i&gt;Ubuntu&lt;/i&gt;. Rozwiązanie oczywiście jest banalne - wystarczy wyłączyć wygaszać dla użytkownika "&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;windows&lt;/span&gt;". W menu otwieramy kolejno: &lt;i&gt;System → Preferencje → Wygaszacz ekranu&lt;/i&gt; i dla pewności ustawiamy:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Przejęcie w stan bezczynności po: &lt;u&gt;2 godzinach&lt;/u&gt;&lt;/li&gt;
&lt;li&gt;Uruchomienie wygaszacza ekranu gdy komputer jest w stanie bezczynności: &lt;u&gt;wyłączyć&lt;/u&gt;&lt;/li&gt;
&lt;li&gt;Blokowanie ekranu, gdy wygaszacz jest aktywny: &lt;u&gt;wyłączyć&lt;/u&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
&lt;span style="font-size: large;"&gt; &lt;/span&gt;&lt;br /&gt;
&lt;span style="font-size: large;"&gt;Podsumowanie&lt;/span&gt;&lt;br /&gt;
Przedstawiony poradnik oczywiście nie wyczerpuje tematu konfiguracji &lt;i&gt;VirtualBoxa&lt;/i&gt; w Linuksie. Nie jest to prawdopodobnie również jedyne rozwiązanie postawionych problemów, a pewne rzeczy może dało by się zrobić lepiej. Co sądzicie? Czekam na komentarze i spostrzeżenia z używania tego poradnika. Tylko proszę nie pisać do mnie &lt;i&gt;per Pan&lt;/i&gt;, bo przecież nie jesteśmy na zajęciach, tylko na blogu :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19722740-5810941635683673951?l=rpetryniak.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://rpetryniak.blogspot.com/feeds/5810941635683673951/comments/default" title="Komentarze do posta" /><link rel="replies" type="text/html" href="http://rpetryniak.blogspot.com/2010/11/wygodna-integracja-windows7-z-ubuntu-za.html#comment-form" title="Komentarze (2)" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/19722740/posts/default/5810941635683673951?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/19722740/posts/default/5810941635683673951?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RafalPetryniakBlog/~3/Dw0bEzWESyo/wygodna-integracja-windows7-z-ubuntu-za.html" title="Wygodna integracja Windows7 z Ubuntu za pomocą VirtualBoxa" /><author><name>Rafał Petryniak</name><uri>https://profiles.google.com/106420849521837640393</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-ueopwOVHATs/AAAAAAAAAAI/AAAAAAAAGaw/TSrE-0eH8Zc/s512-c/photo.jpg" /></author><thr:total>2</thr:total><feedburner:origLink>http://rpetryniak.blogspot.com/2010/11/wygodna-integracja-windows7-z-ubuntu-za.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkIASXw6cCp7ImA9Wx5aFUk.&quot;"><id>tag:blogger.com,1999:blog-19722740.post-5703446618967194549</id><published>2010-11-12T08:55:00.000+01:00</published><updated>2010-11-12T08:55:48.218+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-11-12T08:55:48.218+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="linux" /><title>Konfiguracja lokalnego serwera pakietów Apt-Cacher NG</title><content type="html">W ostatnim czasie stanąłem naprzeciwko wyzwania szybkiej wymiany komputerów i oprogramowania na salach dydaktycznych, którymi się opiekuję na Politechnice Krakowskiej. Całościowy poradnik z przebiegu tej pracy przygotuję niebawem, jednakże już dzisiaj chciałem się podzielić doświadczeniami z konfiguracji lokalnego serwera pakietów &lt;b&gt;&lt;i&gt;Apt-Cacher NG&lt;/i&gt;&lt;/b&gt;.&lt;br /&gt;
&lt;br /&gt;
Jednym z systemów, który miał zostać zainstalowany na każdym z 20 nowych komputerów miał być &lt;i&gt;Ubuntu 10.04.1 LTS&lt;/i&gt; w wersji 64 bitowej. Najpierw postanowiłem przeprowadzić próbną instalację na jednej z maszyn, a dopiero później na pozostałych. Nie wiem z jakich powodów, ale po instalacji systemu, instalacja dodatkowych pakietów, a raczej ich pobieranie z Internetu trwało ok. 3 godziny! Na to nie mogłem sobie pozwolić podczas właściwej instalacji, ponieważ na montaż sprzętu i instalację systemu przed pierwszymi zajęciami miałem niewiele więcej czasu. Dodam jeszcze, że instalator zakomunikował mi pobranie z Internetu ok. &lt;i&gt;350MB&lt;/i&gt; danych do aktualizacji. &lt;br /&gt;
&lt;br /&gt;
Sytuację udało się opanować dzięki skonfigurowaniu jednego komputera jako lokalnego systemu pakietów. Jego rolą miało być &lt;b&gt;buforowanie&lt;/b&gt; (w slangu polsko-angielskim można by powiedzieć &lt;i&gt;keszowanie&lt;/i&gt; ;-) ) pakietów pobranych z Internetu i udostępnienie ich innym maszynom w sieci lokalnej. W tym momencie w &lt;i&gt;Ubuntu&lt;/i&gt; najłatwiej to osiągnąć stosując narzędzie &lt;i&gt;Apt-Cacher NG&lt;/i&gt; (&lt;a href="http://www.unix-ag.uni-kl.de/%7Ebloch/acng/"&gt;strona projektu&lt;/a&gt;). Poniższy poradnik udało mi się przygotować na podstawie kilku materiałów z Internetu, do których odsyłam w razie problemów:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;a href="http://ubuntuforums.org/showthread.php?t=981085"&gt;UbuntuForums.org: &lt;i&gt;How To Install Apt-Cacher-NG in Ubuntu Linux&lt;/i&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.ubuntugeek.com/apt-cacher-ng-http-download-proxy-for-software-packages.html"&gt;UbuntuGeek.com: &lt;i&gt;Apt-Cacher-NG - HTTP download proxy for software packages&lt;/i&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://jakilinux.org/linux/ubuntu/apt-cacher-w-ubuntu/"&gt;JakiLinux.org: &lt;i&gt;Apt-cacher w Ubuntu&lt;/i&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
&lt;span style="font-size: large;"&gt;Konfiguracja lokalnego serwera pakietów&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Uaktualniamy lokalną bazę repozytoriów i pobieramy najnowsze aktualizacje:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;sudo apt-get update
sudo apt-get upgrade&lt;/pre&gt;&lt;br /&gt;
Instalacja narzędzia &lt;i&gt;apt-cacher-ng&lt;/i&gt; z repozytorium:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;sudo apt-get install apt-cacher-ng&lt;/pre&gt;&lt;br /&gt;
&lt;span style="font-size: large;"&gt;Konfiguracja serwera i klientów&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;u&gt;Uwaga:&lt;/u&gt; &lt;i&gt;Należy pamiętać o właściwym ustawieniu adresu IP lokalnego serwera pakietów. Ja używam IP: &lt;/i&gt;&lt;i&gt;192.168.120.102. Należy go oczywiście zmienić na własny.&lt;/i&gt;&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Konfigurujemy system pakietów &lt;i&gt;apt&lt;/i&gt; (aplikacje &lt;i&gt;apt-get&lt;/i&gt;, &lt;i&gt;aptitude&lt;/i&gt; i inne), aby używał &lt;i&gt;apt-cacher-ng&lt;/i&gt;:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;sudo echo 'Acquire::http { Proxy "http://192.168.120.102:3142"; };' | sudo tee /etc/apt/apt.conf.d/01apt-cacher-ng-proxy&lt;/pre&gt;&lt;br /&gt;
Możemy to oczywiście wyłączyć poleceniem:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;sudo rm /etc/apt/apt.conf.d/01apt-cacher-ng-proxy&lt;/pre&gt;&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;Konfiguracja Synaptic z konsoli:&lt;br /&gt;
&lt;br /&gt;
&lt;u&gt;Uwaga:&lt;/u&gt; &lt;i&gt;Jeśli pracujemy na nowym komputerze zaraz po instalacji, należy najpierw uruchomić na nim Synaptica i odświeżyć listę pakietów. Można to zrobic również przez ssh łącząc się z opcją -X&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;sudo grep --color -i 'proxy' /root/.synaptic/synaptic.conf || sudo nano /root/.synaptic/synaptic.conf&lt;/pre&gt;&lt;br /&gt;
zamieniamy ostatnią linijkę, czyli znaki: ”&lt;b&gt;};&lt;/b&gt;” na:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;useProxy "1";
  httpProxy "192.168.120.102";
  httpProxyPort "3142";
  ftpProxy "192.168.120.102";
  ftpProxyPort "3142";
  noProxy "";
};&lt;/pre&gt;&lt;br /&gt;
Sprawdzamy jeszcze raz, czy wprowadzone zmiany znajdują się w pliku:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;sudo grep --color -i 'proxy' /root/.synaptic/synaptic.conf&lt;/pre&gt;&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;Wczytujemy ponownie listę pakietów:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;sudo apt-get update&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
&lt;span style="font-size: large;"&gt;Import lokalnych plików instalacyjnych&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;u&gt;Uwaga&lt;/u&gt;: &lt;b&gt;&lt;i&gt;Poniższe czynności wykonujemy tylko na serwerze!&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
W tym kroku zostaną zaimportowane lokalne pliki &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;*.deb&lt;/span&gt; do repozytorium &lt;i&gt;apt-cacher-ng&lt;/i&gt;. Dzięki temu narzędzie &lt;i&gt;apt-cacher-ng&lt;/i&gt; nie będzie pobierać ponownie już raz pobranych plików.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;test -x /var/cache/apt-cacher-ng/_import || sudo mkdir -p -m 2755 /var/cache/apt-cacher-ng/_import
sudo mv -uf /var/cache/apt/archives/*.deb /var/cache/apt-cacher-ng/_import/&lt;/pre&gt;&lt;br /&gt;
Rozpoczynamy importowanie uruchamiając skrypt znajdujący się w dostarczonym panelu kontrolnym: &lt;a href="http://localhost:3142/acng-report.html?doImport=Start+Import#bottom"&gt;http://localhost:3142/acng-report.html?doImport=Start+Import#bottom&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: large;"&gt;Panel kontrolny i dostęp do dokumentacji&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Twórcy narzędzia &lt;i&gt;Apt-Cacher NG&lt;/i&gt; przygotowali bardzo prosty panel kontrolny (&lt;i&gt;Dashboard&lt;/i&gt;), w którym użytkownik może zobaczyć statystyki z jego działania. Jest on dostępny pod adresem: &lt;a href="http://localhost:3142/acng-report.html"&gt;http://localhost:3142/acng-report.html&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Warto również zajrzeć do oficjalnej dokumentacji, która po instalacji pakietu będzie znajdować się w poniższej lokalizacji (można kliknąć link i otworzyć w przeglądarce): &lt;a href="file:///usr/share/doc/apt-cacher-ng/html/index.html"&gt;file:///usr/share/doc/apt-cacher-ng/html/index.html&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: large;"&gt;Własne spostrzeżenia&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Już teraz, po pierwszych próbach muszę przyznać, że narzędzie to oszczędziło mi sporo czasu i oczywiście sporo nerwów (oczekiwanie na zakończenie aktualizacji, lub też na instalację dodatkowych programów niezbędnych do zajęć, potrafi być stresujące, jeśli te zajęcia rozpoczynają się za kilka minut). Dla przykładu pobranie aktualizacji na 20 maszynach z &lt;i&gt;Ubuntu&lt;/i&gt;, nie trwało tak jak wcześniej wspominałem 3 godziny, a zaledwie 2 minuty. Taką różnicę naprawdę się czuje :-) &lt;br /&gt;
&lt;br /&gt;
Poza aktualizacjami zainstalowałem też  kilkanaście dodatkowych pakietów. Nie wiem ile to było MB dla jednego komputera, ale wiem ile to było w sumie dla wszystkich. Poniżej załączam zrzut ekranu z Panelu kontrolnego, prezentujące statystyki pobrań pakietów z lokalnego serwera pakietów:&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://riad.pk.edu.pl/%7Erpetryniak/website_resources/images/linux/ubuntu-apt_cacher_ng.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://riad.pk.edu.pl/%7Erpetryniak/website_resources/images/linux/ubuntu-apt_cacher_ng.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;
Jak widać ok. 16 GB! danych zostało pobranych z lokalnego serwera pakietów. Jestem przekonany, że fakt ten tak samo cieszy (a może bardziej) administratorów naszej uczelnianej sieci i oczywiście administratorów głównych serwerów pakietów dla &lt;i&gt;Ubuntu&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
Pozostałe uwagi i spostrzeżenia przedstawiam już w skróconej formie:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Idea działania &lt;i&gt;Apt-Cacher NG&lt;/i&gt; jest taka, że po instalacji danego pakietu z dowolnego komputera w sieci lokalnej, pakiet ten powinien być już dostępny dla innych maszyn na serwerze. Ja jednak dla pewności przyjąłem taką strategię, że dany pakiet najpierw instaluje na serwerze, a później na wszystkich klientach na raz.&lt;/li&gt;
&lt;li&gt;Wydawać by się mogło, że importowanie pakietów trzeba wykonać tylko raz. Jednak zdarzyło mi się już kilka razy, że niektóre pakiety pomimo pierwszej instalacji z głównego serwera, znowu były z niego pobierane jeśli instalowałem go ponownie na innej maszynie. Po zauważeniu takiego faktu, warto ponownie zaimportować pakiety.&lt;/li&gt;
&lt;li&gt;Wyliczanie statystyk transferu przez panel kontrolny potrafi zawiesić &lt;i&gt;Apt-Cacher NG&lt;/i&gt;. Ostatnio 2-krotnie po uruchomieniu ich zliczania &lt;i&gt;Apt-Cacher NG&lt;/i&gt; przestawał odpowiadać na zapytania maszyn klienckich. Możliwe, że po prostu nie radził sobie z analizą logów i gdzieś się zawieszał.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;Moim zdaniem &lt;i&gt;Apt-Cacher NG&lt;/i&gt; jest narzędziem jak najbardziej godnym polecenia. &lt;br /&gt;
&lt;ul&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19722740-5703446618967194549?l=rpetryniak.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://rpetryniak.blogspot.com/feeds/5703446618967194549/comments/default" title="Komentarze do posta" /><link rel="replies" type="text/html" href="http://rpetryniak.blogspot.com/2010/11/konfiguracja-lokalnego-serwera-pakietow.html#comment-form" title="Komentarze (0)" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/19722740/posts/default/5703446618967194549?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/19722740/posts/default/5703446618967194549?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RafalPetryniakBlog/~3/MnU2LgpcTkI/konfiguracja-lokalnego-serwera-pakietow.html" title="Konfiguracja lokalnego serwera pakietów Apt-Cacher NG" /><author><name>Rafał Petryniak</name><uri>https://profiles.google.com/106420849521837640393</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-ueopwOVHATs/AAAAAAAAAAI/AAAAAAAAGaw/TSrE-0eH8Zc/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://rpetryniak.blogspot.com/2010/11/konfiguracja-lokalnego-serwera-pakietow.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUIFSXg8eCp7ImA9Wx5XEkQ.&quot;"><id>tag:blogger.com,1999:blog-19722740.post-2159276440198864748</id><published>2010-09-12T14:40:00.002+02:00</published><updated>2010-09-12T15:18:38.670+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-09-12T15:18:38.670+02:00</app:edited><title>Nowe witryny po wakacjach</title><content type="html">Na moim &lt;i&gt;blogu&lt;/i&gt; w czasie wakacji (jak również wcześniej) niewiele się działo. Nie oznacza to wcale, że moja aktywność w sieci została zupełnie zawieszona. Korzystając z odrobiny wolnego czasu, którą udało mi się znaleźć pomiędzy innymi obowiązkami, uporządkowałem uprzednio prowadzone &lt;i&gt;Wiki&lt;/i&gt; (&lt;span style="font-size: x-small;"&gt;nie podaje linku, ponieważ zostanie ono niedługo wyłączone&lt;/span&gt;) i przygotowałem dwie nowe witryny:&lt;br /&gt;
&lt;br /&gt;
&lt;table class="post-body entry-content"&gt;&lt;tbody&gt;
&lt;tr align="center"&gt;&lt;td colspan="2"&gt;&lt;b&gt;Moje zainteresowania naukowe i realizowane projekty &lt;/b&gt;[&lt;a href="http://sites.google.com/site/rafalpetryniakresearch/"&gt;link&lt;/a&gt;]&lt;b&gt;&lt;br /&gt;
&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;a href="http://sites.google.com/site/rafalpetryniakresearch/" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://riad.usk.pk.edu.pl/%7Erpetryniak/website_resources/images/mywebsite-research.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;td valign="top"&gt;Strona zawiera opis moich zainteresowań naukowych oraz zestawienie programów, które udostępniłem jako &lt;i&gt;Open Source&lt;/i&gt;.&lt;br /&gt;
Aby dotrzeć do szerszego grona odbiorców jest ona prowadzona w języku angielskim.&lt;/td&gt;&lt;/tr&gt;
&lt;tr align="center"&gt;&lt;td colspan="2"&gt;&lt;b&gt;Materiały dydaktyczne, kursy, poradniki &lt;/b&gt;[&lt;a href="http://sites.google.com/site/rafalpetryniakcourses/"&gt;link&lt;/a&gt;]&lt;b&gt;&lt;br /&gt;
&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;a href="http://sites.google.com/site/rafalpetryniakcourses/" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://riad.usk.pk.edu.pl/%7Erpetryniak/website_resources/images/mywebsite-courses.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;td valign="top"&gt;Tutaj będą umieszczane wszystkie materiały dydaktyczne, które przygotowuję na potrzeby prowadzonych przeze mnie zajęć.&lt;br /&gt;
Dodatkowo, planuję umieścić na niej inne opracowania (np. poradniki techniczne), które do tej pory pisałem do własnych celów.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;Obie witryny pomimo tego, że mają opracowaną strukturę treści, to zawierają tylko część materiałów, które docelowo planuję tam umieścić. Obie również prowadzone są w oparciu o &lt;i&gt;mechanizm Wiki&lt;/i&gt;, dlatego treść nie zawsze będzie kompletna i dopracowana (teksty redaguję bezpośrednio na tych stronach, a nie wklejam gotowe z zewnętrznych edytorów).&lt;br /&gt;
&lt;br /&gt;
Mam nadzieje, że będą one ciekawym uzupełnieniem dla obecnych (i przyszłych) czytelników bloga.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19722740-2159276440198864748?l=rpetryniak.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://rpetryniak.blogspot.com/feeds/2159276440198864748/comments/default" title="Komentarze do posta" /><link rel="replies" type="text/html" href="http://rpetryniak.blogspot.com/2010/09/nowe-witryny-po-wakacjach.html#comment-form" title="Komentarze (0)" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/19722740/posts/default/2159276440198864748?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/19722740/posts/default/2159276440198864748?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RafalPetryniakBlog/~3/pfTDk8pUU-c/nowe-witryny-po-wakacjach.html" title="Nowe witryny po wakacjach" /><author><name>Rafał Petryniak</name><uri>https://profiles.google.com/106420849521837640393</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-ueopwOVHATs/AAAAAAAAAAI/AAAAAAAAGaw/TSrE-0eH8Zc/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://rpetryniak.blogspot.com/2010/09/nowe-witryny-po-wakacjach.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0INQH86cCp7ImA9WhZWFUU.&quot;"><id>tag:blogger.com,1999:blog-19722740.post-3133435790246937521</id><published>2010-08-31T16:54:00.003+02:00</published><updated>2011-05-16T23:33:11.118+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-05-16T23:33:11.118+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="aplikacje" /><category scheme="http://www.blogger.com/atom/ns#" term="otwarty kod" /><category scheme="http://www.blogger.com/atom/ns#" term="analiza obrazu" /><category scheme="http://www.blogger.com/atom/ns#" term="pandore" /><title>Moduły GUI do anlalizatora obrazu Pandore - Łączenie segmentów</title><content type="html">&lt;table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; margin-left: 1em; text-align: right;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="https://github.com/rpetryniak/Pandore-GUI-Modules" imageanchor="1" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://riad.pk.edu.pl/%7Erpetryniak/website_resources/images/logo/github-logo1.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;&lt;a href="https://github.com/rpetryniak/Pandore-GUI-Modules"&gt;Pełny kod źródłowy&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;Korzystając wyłącznie z algorytmu działów wodnych podczas segmentacji obrazu trudno uzyskać zadowalające efekty. Algorytm ten zależy nie tylko od ilości i położenia punktów startowych, ale również od obrazu wskazującego krawędzie. Jak można było przeczytać (i zobaczyć) w &lt;a href="http://rpetryniak.blogspot.com/2010/08/moduy-gui-do-anlalizatora-obrazu.html"&gt;poprzednim wpisie&lt;/a&gt;, często dla obrazów o zróżnicowanym tle i niejednorodnych obiektach ilość segmentów jest znacznie wyższa od tej, którą byśmy sami wskazali. Warto zdawać sobie sprawę, że wskazane problemy w podobnym stopniu dotyczą wszystkich algorytmów segmentacji. Dlatego, aby poprawić jakość wyników celowe może się okazać wprowadzenie kolejnego etapu przetwarzania obrazu. Najczęściej stosuje się różnego rodzaju &lt;b&gt;metody łączenia segmentów&lt;/b&gt;, tak aby ich wielkość lepiej odpowiadała wielkości rzeczywistych obiektów. Na szczęście analizator obrazu &lt;a href="http://rpetryniak.blogspot.com/2008/07/pandore_21.html"&gt;Pandore&lt;/a&gt; posiada zestaw popularnych operatorów służących do tego celu. Jednak są to operatory bez graficznego interfejsu użytkownika, przez co ich stosowanie może być kłopotliwe zarówno dla nowego użytkownika, który musi nauczyć się składni poszczególnych poleceń, jak również dla bardziej doświadczonego użytkownika, których od razu chce zobaczyć efekty ich działania po zmianie odpowiednich parametrów. Dlatego, podobnie jak w przypadku działów wodnych, przygotowałem graficzny interfejs, który ma ułatwiać korzystanie z operatorów łączenia segmentów dostępnych w &lt;i&gt;Pandore&lt;/i&gt;. Jego pełny &lt;b&gt;kod źródłowy&lt;/b&gt; na &lt;u&gt;licencji BSD&lt;/u&gt; został umieszczony w publicznym &lt;a href="http://github.com/rpetryniak/Pandore-GUI-Modules"&gt;repozytorium na GitHub&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Interfejs użytkownika&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Okienko programu podobnie jak w przypadku modułu działów wodnych zostało podzielone na dwie części: panel opcji i ramkę wyświetlającą obrazy wejściowe lub wyniki działania wybranego algorytmu. Obrazy wejściowe mogą zostać otwarte za pomocą menu &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;[File]&lt;/span&gt;. Mamy tutaj do wyboru następujące opcje:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;[Open oryginal image]&lt;/span&gt; - otwarcie oryginalnego obrazka, który służy jedynie do prezentacji wyników,&lt;/li&gt;
&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;[Open image for computation]&lt;/span&gt; - otwarcie obrazka, na podstawie którego będą wykonywane obliczenia spójności sąsiednich regionów; obraz ten warto wcześniej przygotować (można np. usunąć szum),&lt;/li&gt;
&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;[Open prelabeled image]&lt;/span&gt; - poindeksowany obraz segmentów przygotowany za pomocą algorytmu działów wodnych lub innego algorytmu segmentacji.&lt;/li&gt;
&lt;/ul&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://lh6.ggpht.com/_AeFiJN9phoM/TFLCcdeOsXI/AAAAAAAACFE/_ls2B1OLctY/pandore_gui_modules-regiongrowing_1a.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="258" src="http://lh6.ggpht.com/_AeFiJN9phoM/TFLCcdeOsXI/AAAAAAAACFE/_ls2B1OLctY/pandore_gui_modules-regiongrowing_1a.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
Każdy z obrazów wejściowych jest wyświetlany automatycznie po otwarciu. Można je oczywiście w każdym momencie obejrzeć korzystając z ramki &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;[Display]&lt;/span&gt; na panelu opcji. Poza wyświetleniem obrazów wejściowych w oryginalnej formie (3 pierwsze obrazki na rysunku poniżej), dodano jeszcze trzy opcje prezentujące w sposób graficzny wyniki łączenia segmentów (3 kolejne obrazki na rysunku poniżej):&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;[Color labeled image]&lt;/span&gt; - dla każdego segmentu zostaje przypisany losowy kolor; jeśli wybrane kolory nie są najlepiej dobrane można losować do skutku,&lt;/li&gt;
&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;[Image with transparen labels]&lt;/span&gt; - kolorowe segmenty nanoszone są na obraz wejściowy; użytkownik ma możliwość zmiany ich przezroczystości,&lt;/li&gt;
&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;[Image with border of labels]&lt;/span&gt; - na obrazie oryginalnym zaznaczane są kontury segmentów; istnieje możliwość określenia koloru.&lt;/li&gt;
&lt;/ul&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://lh4.ggpht.com/_AeFiJN9phoM/TFLClN7FvLI/AAAAAAAACFY/SQdZNK4POiY/pandore_gui_modules-regiongrowing_4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="183" src="http://lh4.ggpht.com/_AeFiJN9phoM/TFLClN7FvLI/AAAAAAAACFY/SQdZNK4POiY/pandore_gui_modules-regiongrowing_4.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;b&gt;Możliwości&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
W chwili obecnej program zawiera prawie wszystkie operatory łączenia segmentów dostępne w &lt;i&gt;Pandore&lt;/i&gt;. Nie ma na razie operatora &lt;a href="http://www.greyc.ensicaen.fr/~regis/Pandore/programmes/en/operatorsP0/pmumfordshahmerging.html"&gt;pmumfordshahmerging&lt;/a&gt;, który ma inną strukturę parametrów wywołania w porównaniu do pozostałych operatorów. Listę dostępnych w programie operatorów można zobaczyć na rysunku poniżej. Są to odpowiednio:&lt;a href="http://www.greyc.ensicaen.fr/~regis/Pandore/programmes/en/operatorsP0/pcontrastmerging.html"&gt;pcontrastmerging&lt;/a&gt;, &lt;a href="http://www.greyc.ensicaen.fr/~regis/Pandore/programmes/en/operatorsP0/pentropymerging.html"&gt;pentropymerging&lt;/a&gt;, &lt;a href="http://www.greyc.ensicaen.fr/~regis/Pandore/programmes/en/operatorsP0/pmeanmerging.html"&gt;pmeanmerging&lt;/a&gt;, &lt;a href="http://www.greyc.ensicaen.fr/~regis/Pandore/programmes/en/operatorsP0/puniformitymerging.html"&gt;puniformitymerging&lt;/a&gt;, &lt;a href="http://www.greyc.ensicaen.fr/~regis/Pandore/programmes/en/operatorsP0/pvariancemerging.html"&gt;pvariancemerging&lt;/a&gt;, &lt;a href="http://www.greyc.ensicaen.fr/~regis/Pandore/programmes/en/operatorsP0/pboundarymerging.html"&gt;pboundarymerging&lt;/a&gt;, &lt;a href="http://www.greyc.ensicaen.fr/~regis/Pandore/programmes/en/operatorsP0/phistomerging.html"&gt;phistomerging&lt;/a&gt; (wymieniam ponownie dodając odnośniki do oficjalnej dokumentacji).&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://lh5.ggpht.com/_AeFiJN9phoM/TFLCcqS8WDI/AAAAAAAACFM/wwLU51C7cS4/pandore_gui_modules-regiongrowing_2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://lh5.ggpht.com/_AeFiJN9phoM/TFLCcqS8WDI/AAAAAAAACFM/wwLU51C7cS4/pandore_gui_modules-regiongrowing_2.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
Wybór określonego algorytmu powoduje jego automatyczne uruchomienie, a co zatem idzie wyświetlenie wyników jego działania. Dla każdego algorytmu dostępny jest opis jego działania (przycisk &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;[?]&lt;/span&gt;) pochodzący z&lt;a href="http://www.greyc.ensicaen.fr/~regis/Pandore/programmes/en/index_operatorsP0.html"&gt; oficjalnej dokumentacji Pandore&lt;/a&gt; (pomoc jest &lt;i&gt;on-line&lt;/i&gt;, dlatego do jej działania wymagane jest aktywne połączenie z Internetem). Dostępne są również podpowiedzi na suwakach opcji &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;[Number of merging]&lt;/span&gt; i &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;[Threshold]&lt;/span&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://lh4.ggpht.com/_AeFiJN9phoM/TFLCcz-6F2I/AAAAAAAACFQ/Qr33LRT3xAE/pandore_gui_modules-regiongrowing_3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="227" src="http://lh4.ggpht.com/_AeFiJN9phoM/TFLCcz-6F2I/AAAAAAAACFQ/Qr33LRT3xAE/pandore_gui_modules-regiongrowing_3.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
Opisany interfejs działa w trybie pełnej interakcji. Zmiana algorytmu lub jego parametrów skutkuje natychmiastowym wyświetleniem wyników. Na szybkich komputerach sprawdza się to bardzo dobrze. Na starszych maszynach czas oczekiwania może być zauważalny.&lt;br /&gt;
&lt;br /&gt;
Sposób działania opisanego programu można prześledzić na dołączonym filmie video.&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: center;"&gt;&lt;object height="306" width="500"&gt;&lt;param name="movie" value="http://www.youtube.com/v/lbNqBgBZx6w&amp;amp;hl=pl_PL&amp;amp;fs=1"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/lbNqBgBZx6w&amp;amp;hl=pl_PL&amp;amp;fs=1" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="500" height="306"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;
&lt;a href="http://www.youtube.com/watch_popup?v=lbNqBgBZx6w&amp;amp;vq=hd720" target="_blank"&gt;&lt;i&gt;Oglądaj film w rozdzielczości HD na pełnym ekranie.&lt;/i&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19722740-3133435790246937521?l=rpetryniak.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://rpetryniak.blogspot.com/feeds/3133435790246937521/comments/default" title="Komentarze do posta" /><link rel="replies" type="text/html" href="http://rpetryniak.blogspot.com/2010/08/moduy-gui-do-anlalizatora-obrazu_31.html#comment-form" title="Komentarze (0)" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/19722740/posts/default/3133435790246937521?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/19722740/posts/default/3133435790246937521?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RafalPetryniakBlog/~3/UXxtYD74I1A/moduy-gui-do-anlalizatora-obrazu_31.html" title="Moduły GUI do anlalizatora obrazu Pandore - Łączenie segmentów" /><author><name>Rafał Petryniak</name><uri>https://profiles.google.com/106420849521837640393</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-ueopwOVHATs/AAAAAAAAAAI/AAAAAAAAGaw/TSrE-0eH8Zc/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh6.ggpht.com/_AeFiJN9phoM/TFLCcdeOsXI/AAAAAAAACFE/_ls2B1OLctY/s72-c/pandore_gui_modules-regiongrowing_1a.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://rpetryniak.blogspot.com/2010/08/moduy-gui-do-anlalizatora-obrazu_31.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0EBSX85eCp7ImA9WhZWFUU.&quot;"><id>tag:blogger.com,1999:blog-19722740.post-5481829849632414407</id><published>2010-08-11T14:48:00.016+02:00</published><updated>2011-05-16T23:34:18.120+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-05-16T23:34:18.120+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="aplikacje" /><category scheme="http://www.blogger.com/atom/ns#" term="otwarty kod" /><category scheme="http://www.blogger.com/atom/ns#" term="analiza obrazu" /><category scheme="http://www.blogger.com/atom/ns#" term="pandore" /><title>Moduły GUI do anlalizatora obrazu Pandore - Działy wodne</title><content type="html">&lt;table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; margin-left: 1em; text-align: right;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="https://github.com/rpetryniak/Pandore-GUI-Modules" imageanchor="1" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://riad.pk.edu.pl/%7Erpetryniak/website_resources/images/logo/github-logo1.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;&lt;a href="https://github.com/rpetryniak/Pandore-GUI-Modules"&gt;Pełny kod źródłowy&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;Analizatora obrazu &lt;a href="http://rpetryniak.blogspot.com/2008/07/pandore_21.html"&gt;Pandore&lt;/a&gt; używam już od dłuższego czasu. Pomimo tego, że do większości zadań pisanie skryptów w konsoli jak najbardziej mi odpowiada, to czasami brakuje mi okienkowego interfejsu użytkownika, który mógłby przyspieszyć poszukiwanie optymalnych parametrów, dla poszczególnych operatorów. Częściowo w takich sytuacjach można posłużyć się interfejsem &lt;i&gt;Ariane&lt;/i&gt;, o którym &lt;a href="http://rpetryniak.blogspot.com/2009/06/ariane-interfejs-graficzny-dla-pandore.html"&gt;pisałem jakiś czas temu&lt;/a&gt;. Niestety każdorazowa edycja parametrów zapisanych w bloczkach i późniejsze wyświetlenie wyniku wymagają kilku kliknięć, a to wcale nie przyśpiesza pracy. Dlatego postanowiłem napisać własne (mini) programy, aby jeszcze bardziej usprawnić interakcję z użytkownikiem. Korzystając z biblioteki &lt;a href="http://rpetryniak.blogspot.com/2008/08/qt_20.html"&gt;Qt&lt;/a&gt;, przygotowałem dwie aplikacje (możliwe, że pojawi się więcej), które bardziej szczegółowo opiszę w tym i następnym wpisie. Pełny &lt;b&gt;kod źródłowy&lt;/b&gt; na &lt;u&gt;licencji BSD&lt;/u&gt; został umieszczony w &lt;a href="http://github.com/rpetryniak/Pandore-GUI-Modules"&gt;publicznym tepozytorium na GitHub&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Pierwsza aplikacja (używam też nazwy &lt;i&gt;moduł GUI&lt;/i&gt;) została poświęcona algorytmowi &lt;b&gt;&lt;i&gt;Działów wodnych&lt;/i&gt;&lt;/b&gt;. Jej celem jest nie tylko uruchomienie tego algorytmu, ale również odpowiednie przygotowanie danych wejściowych. Dla niewtajemniczonych przypomnę, że algorytm ten umożliwia segmentację obrazu - rozbicie na obszary, które powinny odpowiadać rzeczywistym obiektom. Jego działanie zależy od właściwego przygotowanie obrazów wejściowych. Jednym z nich powinien być obraz wskazujący punkty (lub obszary) startowe, od których rozpoczyna się proces tzw. &lt;i&gt;zalewania&lt;/i&gt;. Drugi obraz określa obszar i kierunek, w którym to zalewanie następuje (&lt;i&gt;więcej na ten temat poniżej&lt;/i&gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Interfejs użytkownika&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Okienko programu zostało podzielone na dwie części - lewa zawiera panel opcji, natomiast prawa podgląd obrazów wejściowych lub wyniki segmentacji. Obraz po wczytaniu (menu &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;[File]&lt;/span&gt; → &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;[Open oryginal image]&lt;/span&gt;) można poddać operacji negatywu &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;[Invert]&lt;/span&gt; lub rozmyciu &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;[Blur]&lt;/span&gt;. Ta druga operacja jest szczególnie zalecana ponieważ usuwa nadmiar szumu z obrazu, a tym samym zmniejsza ilość wynikowych segmentów. Następna opcja na panelu &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;[Show]&lt;/span&gt; pozwala obejrzeć obraz, na podstawie którego wyliczany jest obszar zalewania (opcja &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;[Image for computations]&lt;/span&gt;). Obraz ten można przygotować na dwa sposoby (panel &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;[Set image for computations]&lt;/span&gt;):&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Obraz gradientowy &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;[Gradient image]&lt;/span&gt; - wskazuje na granice obiektów,&lt;/li&gt;
&lt;li&gt;Mapa odległości &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;[Distance map]&lt;/span&gt; - określa odległość od wcześniej obliczonych obiektów z wykorzystaniem opcji &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;[Binary image]&lt;/span&gt; na panelu &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;[Set initial image]&lt;/span&gt;. &lt;/li&gt;
&lt;/ul&gt;Punkty startowe &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt; &lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;[Show]&lt;/span&gt; → &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;[Initial image]&lt;/span&gt; dla algorytmu działów wodnych można wyznaczyć na kilka sposobów (panel &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;[Set initial image]&lt;/span&gt;):&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Lokalne minima &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;[Local minimum point]&lt;/span&gt; - punkty, których wszystkie sąsiednie punkty mają wyższe wartości,&lt;/li&gt;
&lt;li&gt;Obraz binarny &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;[Binary image]&lt;/span&gt; - każdy obiekt jasny (biały) będzie podstawą do zbudowania osobnego segmentu,&lt;/li&gt;
&lt;li&gt;Ręczne zaznaczenie obszarów startowych &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;[Marker]&lt;/span&gt;. &lt;/li&gt;
&lt;/ul&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://lh6.ggpht.com/_AeFiJN9phoM/TFLCQ5eABcI/AAAAAAAACEs/quIycn27nD0/pandore_gui_modules-watershed_1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://lh6.ggpht.com/_AeFiJN9phoM/TFLCQ5eABcI/AAAAAAAACEs/quIycn27nD0/pandore_gui_modules-watershed_1.png" width="500" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
A teraz krótko, co jest pod maską aplikacji, czyli &lt;u&gt;jakie operatory Pandore są używane&lt;/u&gt;:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.greyc.ensicaen.fr/%7Eregis/Pandore/programmes/en/operatorsP0/pgaussianfiltering.html"&gt;pgaussianfiltering&lt;/a&gt; - rozmycie obrazu filtrem Gaussa,&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.greyc.ensicaen.fr/%7Eregis/Pandore/programmes/en/operatorsP0/pbinarization.html"&gt;pbinarization&lt;/a&gt; - binaryzacja obrazu,&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.greyc.ensicaen.fr/%7Eregis/Pandore/programmes/en/operatorsP0/psobel.html"&gt;psobel&lt;/a&gt; - jeden z operatorów gradientu, &lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.greyc.ensicaen.fr/%7Eregis/Pandore/programmes/en/operatorsP0/pdistance.html"&gt;pdistance&lt;/a&gt; - mapa odległości,&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.greyc.ensicaen.fr/%7Eregis/Pandore/programmes/en/operatorsP0/plocalminima.html"&gt;plocalminima&lt;/a&gt; - wyliczanie lokalnych minimów,&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.greyc.ensicaen.fr/%7Eregis/Pandore/programmes/en/operatorsP0/pwatershed.html"&gt;pwatershed&lt;/a&gt; - algorytm działów wodnych.&lt;br /&gt;
&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
&lt;b&gt;Możlwości &lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Poniżej zostaną wskazane przykładowe sposoby wykorzystania aplikacji. Nie każda kombinacja omówionych powyżej opcji ma sens, dlatego posłużę się dwoma różnymi obrazami - obrazem naturalnym przedstawiającym chłopca w kapeluszu (przykład 1 i 2) i obrazem pokazującym kilka podobnych elementów (przykład 3, 4 i 5).&lt;br /&gt;
&lt;br /&gt;
1. &lt;u&gt;Automatyczna segmentacja obiektów&lt;/u&gt;.&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;obraz do obliczeń: &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;[Gradient image]&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;punkty startowe: &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;[Local minima point]&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://lh5.ggpht.com/_AeFiJN9phoM/TFLCRBJezGI/AAAAAAAACEw/pv-JImcXKDA/pandore_gui_modules-watershed_2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://lh5.ggpht.com/_AeFiJN9phoM/TFLCRBJezGI/AAAAAAAACEw/pv-JImcXKDA/pandore_gui_modules-watershed_2.png" width="500" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;u&gt;Komentarz:&lt;/u&gt; &lt;i&gt;Pomimo rozmycia obrazu filtrem Gaussa o wartości sigma = 1,1 otrzymano znaczne rozdrobnienie segmentów. Dalsze zwiększanie tej wartości skutkowało powstawaniem błędnych obiektów, które zawierały fragmenty dwóch obiektów.&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
2. &lt;u&gt;Manualna segmentacja obiektów&lt;/u&gt;.&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;obraz do obliczeń: &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;[Gradient image]&lt;/span&gt;&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;punkty startowe: &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;[Marker]&lt;/span&gt;&lt;br /&gt;
&lt;/li&gt;
&lt;/ul&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://lh6.ggpht.com/_AeFiJN9phoM/TFLCRYQ-QaI/AAAAAAAACE0/PPgVEKGan_U/pandore_gui_modules-watershed_3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://lh6.ggpht.com/_AeFiJN9phoM/TFLCRYQ-QaI/AAAAAAAACE0/PPgVEKGan_U/pandore_gui_modules-watershed_3.png" width="500" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;u&gt;Komentarz:&lt;/u&gt; &lt;i&gt;Zastosowanie obrazu gradientowego i manualnie wskazywanych znaczników (markerów) pozwala na poprawną segmentację obiektów.&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
3. &lt;u&gt;Wyznaczenie strefy wpływu poszczególnych obiektów&lt;/u&gt;.&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;obraz do obliczeń: &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;[Distance map]&lt;/span&gt;&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;punkty startowe: &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;[Binary image]&lt;/span&gt;&lt;br /&gt;
&lt;/li&gt;
&lt;/ul&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://lh6.ggpht.com/_AeFiJN9phoM/TFLCRj79zsI/AAAAAAAACE4/UZkTTyztXVU/pandore_gui_modules-watershed_4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://lh6.ggpht.com/_AeFiJN9phoM/TFLCRj79zsI/AAAAAAAACE4/UZkTTyztXVU/pandore_gui_modules-watershed_4.png" width="450" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;u&gt;Komentarz:&lt;/u&gt; &lt;i&gt;Algorytm działów wodnych może służyć do  wyznaczenia tzw. strefy wpływu poszczególnych obiektów. W tym celu  należy wykonać binaryzację obrazu (tutaj wartość progowa wynosiła 100) i  policzyć mapę odległości.&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
4. &lt;u&gt;Automatyczna segmentacja obiektów&lt;/u&gt;.&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;obraz do obliczeń: &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;[Gradient image]&lt;/span&gt;&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;punkty startowe: &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;[Binary image]&lt;/span&gt;&lt;br /&gt;
&lt;/li&gt;
&lt;/ul&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://lh6.ggpht.com/_AeFiJN9phoM/TFLCSIB3JTI/AAAAAAAACE8/YH6tUeLBpio/pandore_gui_modules-watershed_5.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://lh6.ggpht.com/_AeFiJN9phoM/TFLCSIB3JTI/AAAAAAAACE8/YH6tUeLBpio/pandore_gui_modules-watershed_5.png" width="450" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;u&gt;Komentarz:&lt;/u&gt; &lt;i&gt;Korzystając z wcześniej przygotowanego obrazu  binarnego i obrazu gradientowego można wyznaczyć granice obiektów.  Niestety został pominięty jeden element na obrazie. Powodem tego jest brak  punktu startowego wskazującego tło. Można to oczywiści rozwiązać w podejściu automatycznym, jednak aplikacja nie ma na razie takiej opcji.  Jak to zrobić za pomocą Pandore, opiszę niebawem.&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
5. &lt;u&gt;Manualna segmentacja obiektów&lt;/u&gt;.&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;obraz do obliczeń: &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;[Gradient image]&lt;/span&gt;&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;punkty startowe: &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;[Marker]&lt;/span&gt;&lt;br /&gt;
&lt;/li&gt;
&lt;/ul&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://lh5.ggpht.com/_AeFiJN9phoM/TFLCcJLqz-I/AAAAAAAACFA/Awm34Z0-dKQ/pandore_gui_modules-watershed_6.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://lh5.ggpht.com/_AeFiJN9phoM/TFLCcJLqz-I/AAAAAAAACFA/Awm34Z0-dKQ/pandore_gui_modules-watershed_6.png" width="450" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;u&gt;Komentarz:&lt;/u&gt; &lt;i&gt;Wskazany powyżej problem można oczywiście rozwiązać poprzez manualne zaznaczenie wszystkich obiektów i tła.&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
Aby prześledzić sposób obsługi programu zachęcam do obejrzenia krótkiego filmu. Zostały na nim jeszcze raz pokazane wszystkie opisane przed chwilą przypadki użycia, co powinno jeszcze lepiej przybliżyć czytelnikowi możliwości jego działania.&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: center;"&gt;&lt;object height="306" width="500"&gt;&lt;param name="movie" value="http://www.youtube.com/v/6lnY72KvvXk&amp;amp;hl=pl_PL&amp;amp;fs=1"&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;embed src="http://www.youtube.com/v/6lnY72KvvXk&amp;amp;hl=pl_PL&amp;amp;fs=1" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" height="306" width="500"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;
&lt;a href="http://www.youtube.com/watch_popup?v=6lnY72KvvXk&amp;amp;vq=hd720" target="_blank"&gt;&lt;i&gt;Oglądaj film w rozdzielczości HD na pełnym ekranie.&lt;/i&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19722740-5481829849632414407?l=rpetryniak.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://rpetryniak.blogspot.com/feeds/5481829849632414407/comments/default" title="Komentarze do posta" /><link rel="replies" type="text/html" href="http://rpetryniak.blogspot.com/2010/08/moduy-gui-do-anlalizatora-obrazu.html#comment-form" title="Komentarze (0)" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/19722740/posts/default/5481829849632414407?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/19722740/posts/default/5481829849632414407?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RafalPetryniakBlog/~3/KK5qbJ9vShU/moduy-gui-do-anlalizatora-obrazu.html" title="Moduły GUI do anlalizatora obrazu Pandore - Działy wodne" /><author><name>Rafał Petryniak</name><uri>https://profiles.google.com/106420849521837640393</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-ueopwOVHATs/AAAAAAAAAAI/AAAAAAAAGaw/TSrE-0eH8Zc/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh6.ggpht.com/_AeFiJN9phoM/TFLCQ5eABcI/AAAAAAAACEs/quIycn27nD0/s72-c/pandore_gui_modules-watershed_1.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://rpetryniak.blogspot.com/2010/08/moduy-gui-do-anlalizatora-obrazu.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A04HSHwyeyp7ImA9Wx5TFE0.&quot;"><id>tag:blogger.com,1999:blog-19722740.post-2508840545107656526</id><published>2010-07-23T15:51:00.006+02:00</published><updated>2010-07-29T15:25:39.293+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-07-29T15:25:39.293+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="analiza obrazu" /><category scheme="http://www.blogger.com/atom/ns#" term="dicom" /><title>Zbiory ogólnodostępnych obrazów medycznych</title><content type="html">Trudno zajmować się przetwarzaniem obrazów medycznych, nie mając dostępu do takich danych. Najlepiej oczywiście mieć stalą współpracę z dużym szpitalem, który ma dobrze zorganizowany zakład radiologiczny lub też mieć znajomego lekarza, który z chęcią podzieli się takimi obrazami i dodatkowo wskaże problem badawczy. Jeśli jednak nie mamy tego szczęścia, to nic straconego, ponieważ zawsze można skorzystać z publicznie dostępnych zbiorów w Internecie. Do ich poszukiwania skłoniła mnie potrzeba lepszego przetestowania algorytmu nad którym ostatnio pracowałem, a do tej pory miałem do dyspozycji jedynie kilkanaście obrazów.&lt;br /&gt;
&lt;br /&gt;
Poniższa lista nie zawiera opisu baz danych - tego jak i przez kogo zostały organizowane. Zawiera jedynie praktyczne wskazówki odnośnie możliwości dostępu do tych danych i ich wykorzystania we własnej pracy (ograniczenia licencyjne). Pozostałe informacje można znaleźć nie tylko na wskazanych stronach, ale również przy poszczególnych obrazach (jak i gdzie zostały zrobione).&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;a href="http://pubimage.hcuge.ch/login.html"&gt;Casimage&lt;/a&gt; - jedna z najstarszych baz danych, liczy ok. 10 000 obrazów. Sprawia wrażenie już nie rozwijanej (linki do strony organizatorów nie działają). Brak jednego archiwum danych. Dostęp jest możliwy przez interfejs &lt;span style="font-style: italic;"&gt;WWW&lt;/span&gt;.  Obrazy można pobierać indywidualnie. Na  szczęście obrazy umieszczone są na serwerze począwszy od pliku &lt;a href="http://pubimage.hcuge.ch/4DCGI/FULLIMAGE/0"&gt;0&lt;/a&gt; do &lt;a href="http://pubimage.hcuge.ch/4DCGI/FULLIMAGE/9735"&gt;9735&lt;/a&gt;. Dzięki temu można szybko pobrać je korzystając z przygotowanego przeze mnie skryptu [linux, wget]:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;for i in $(seq 9735); do wget "http://pubimage.hcuge.ch/4DCGI/FULLIMAGE/$i"; echo $i; done&lt;/pre&gt;Niestety nie wszystkie pliki chcą się od razu pobrać, dlatego polecam kilkukrotne uruchomienie  nieznacznie zmodyfikowanej wersji poprzedniego skryptu:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint lang-bsh notranslate"&gt;#!/bin/bash
for i in $(seq 9735)
do
  if [ ! -f $i ]
  then
    wget "http://pubimage.hcuge.ch/4DCGI/FULLIMAGE/$i";
    echo $i;
  fi
done&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://mirc.rsna.org/mirc/query"&gt;RSNA&lt;/a&gt; - zbiór baz danych zorganizowanych przez &lt;a href="http://www.rsna.org/" style="font-style: italic;"&gt;Stowarzyszenie Radiologów Ameryki Północnej&lt;/a&gt;. Dostęp do wielu medycznych baz danych za pomocą interfejsu &lt;span style="font-style: italic;"&gt;WWW.&lt;/span&gt;&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.mypacs.net/cgi-bin/repos/mpv3_repo/case-manager.pl"&gt;MyPacs&lt;/a&gt; - prawdopodobnie największy (ok. 120 000) publicznie dostępny zbiór obrazów medycznych. Dostęp przez interfejs &lt;span style="font-style: italic;"&gt;Flash&lt;/span&gt;, bez możliwości pobierania danych. Możliwość taka jest po przełączeniu się do uproszczonego trybu &lt;span style="font-style: italic;"&gt;html&lt;/span&gt;.&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="http://medgift.unige.ch/demo/"&gt;MedGift&lt;/a&gt; -  demo systemu wyszukiwania obrazów &lt;a href="http://www.sim.hcuge.ch/medgift/01_Presentation_EN.htm" style="font-style: italic;"&gt;MedGift&lt;/a&gt;, który bazuje na innym systemie, a mianowicie: &lt;a href="http://www.gnu.org/software/gift/" style="font-style: italic;"&gt;Gift&lt;/a&gt;. Dane pochodzą prawdopodobnie z bazy &lt;span style="font-style: italic;"&gt;Casimage&lt;/span&gt;. Zaletą tego systemu jest możliwość szybkiego stworzenia zbioru podobnych obrazów, co w przypadku pozostałych baz trzeba zrobić samemu (lub można skorzystać z zaproponowanego podziału na kategorie).&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="http://rad.usuhs.edu/medpix/"&gt;MedPix&lt;/a&gt; - druga co do wielkości baza obrazów. Dostępny interfejs &lt;span style="font-style: italic;"&gt;WWW&lt;/span&gt; utrudnia pobieranie obrazów (zablokowany prawy przycisk myszy). Można się jednak do nich dostać przez &lt;span style="font-style: italic;"&gt;Google Images&lt;/span&gt; (&lt;a href="http://www.google.pl/images?hl=pl&amp;amp;q=site%3Ahttp%3A%2F%2Frad.usuhs.edu%2Fmedpix%2F&amp;amp;um=1&amp;amp;ie=UTF-8&amp;amp;source=og&amp;amp;sa=N&amp;amp;tab=wi"&gt;link do wyszukiwania&lt;/a&gt;). Niestety obrazki mają dodane wizualne adnotacje, co jeszcze bardziej utrudnia swobodne ich przetwarzanie.&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="http://ganymed.imib.rwth-aachen.de/irma/datasets_en.php"&gt;IRMA&lt;/a&gt; - zbiór ok. 15 000 obrazów podzielonych na ok. 200 kategorii. Dostęp do archiwum z plikami możliwy jest po podpisaniu warunków użycia (do zastosowań naukowych, nie komercyjnych, bez możliwości udostępniania pełnego zbioru dalej) i przefaksowaniu na podany adres.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://imageclef.org/2010/medical"&gt;ImageCLEF&lt;/a&gt; - ok 80 000 obrazów, dostępnych prawdopodobnie w postacie jednego lub kilku archiwów. Obrazy pochodzą m.in. z bazy &lt;span style="font-style: italic;"&gt;IRMA&lt;/span&gt;, &lt;span style="font-style: italic;"&gt;Casimage.&lt;/span&gt;  Warunki użycia są podobne jak w przypadku bazy &lt;span style="font-style: italic;"&gt;IRMA&lt;/span&gt;, tylko muszą one zostać podpisane przez osobę na stanowisku kierowniczym w jednostce naukowej.&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.insight-journal.org/midas/"&gt;Midas&lt;/a&gt; - baza danych pod patronatem firmy &lt;a href="http://www.kitware.com/"&gt;&lt;span style="font-style: italic;"&gt;Kitware&lt;/span&gt;&lt;/a&gt;, która patronuje m.in. &lt;a href="http://rpetryniak.blogspot.com/2008/07/visualization-toolkit-vtk_28.html"&gt;&lt;span style="font-style: italic;"&gt;VTK&lt;/span&gt;&lt;/a&gt; i &lt;a href="http://rpetryniak.blogspot.com/2008/07/insight-toolkit_23.html"&gt;&lt;span style="font-style: italic;"&gt;Insight Toolkit&lt;/span&gt;&lt;/a&gt;. Związana z elektronicznym czasopismem naukowym &lt;a href="http://www.insight-journal.org/"&gt;&lt;span style="font-style: italic;"&gt;Insight Journal&lt;/span&gt;&lt;/a&gt;. Obrazy dostępne przez interfejs WWW najczęściej w formatach źródłowych: &lt;span style="font-style: italic;"&gt;DICOM&lt;/span&gt; lub binarnym.&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.springerimages.com/imagesMD/welcome/"&gt;Springer Images&lt;/a&gt;  - obrazy dołączone do publikacji &lt;span style="font-style: italic;"&gt;Springer.&lt;/span&gt; Każdy obraz ma indywidualną licencję jednak w trakcie wyszukiwania można wybrać grupę licencji otwartych.&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="http://ihm.nlm.nih.gov/luna/servlet/view/all"&gt;Images from the History of Medicine&lt;/a&gt; (NLM) - obrazy związane z historią medycyny zebrane przez &lt;a href="http://www.nlm.nih.gov/"&gt;&lt;span style="font-style: italic;"&gt;National Library of Medicine USA&lt;/span&gt;&lt;/a&gt;.&lt;br /&gt;
&lt;/li&gt;
&lt;/ul&gt;Poza wyżej wymienionymi bazami danych warto jeszcze zajrzeć na spis plików opracowany na stronie biblioteki &lt;span style="font-style: italic;"&gt;GDCM&lt;/span&gt; (&lt;a href="http://sourceforge.net/apps/mediawiki/gdcm/index.php?title=Sample_DataSet"&gt;link&lt;/a&gt;) oraz programu &lt;span style="font-style: italic;"&gt;OsiriX&lt;/span&gt; (&lt;a href="http://pubimage.hcuge.ch:8080/"&gt;link&lt;/a&gt;).&lt;br /&gt;
&lt;br /&gt;
Mam nadzieje, że przedstawione przeze mnie bazy obrazów medycznych pozwolą czytelnikowi na znalezienie ciekawego materiału badawczego i zaowocują powstaniem ciekawych prac naukowych. Powodzenia.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19722740-2508840545107656526?l=rpetryniak.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://rpetryniak.blogspot.com/feeds/2508840545107656526/comments/default" title="Komentarze do posta" /><link rel="replies" type="text/html" href="http://rpetryniak.blogspot.com/2010/07/zbiory-ogolnodostepnych-obrazow.html#comment-form" title="Komentarze (0)" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/19722740/posts/default/2508840545107656526?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/19722740/posts/default/2508840545107656526?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RafalPetryniakBlog/~3/eVQPnbt64BM/zbiory-ogolnodostepnych-obrazow.html" title="Zbiory ogólnodostępnych obrazów medycznych" /><author><name>Rafał Petryniak</name><uri>https://profiles.google.com/106420849521837640393</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-ueopwOVHATs/AAAAAAAAAAI/AAAAAAAAGaw/TSrE-0eH8Zc/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://rpetryniak.blogspot.com/2010/07/zbiory-ogolnodostepnych-obrazow.html</feedburner:origLink></entry></feed>

