<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>EmguCV &#8211; Strona Szoguna</title>
	<atom:link href="https://szogun1987.pl/show/tag/emgu-cv/feed/" rel="self" type="application/rss+xml" />
	<link>https://szogun1987.pl</link>
	<description>Jeszcze wstawię tutaj jakiś głęboki cytat</description>
	<lastBuildDate>Sat, 21 Jun 2014 16:25:30 +0000</lastBuildDate>
	<language>pl-PL</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.3.2</generator>
	<item>
		<title>Amatorskie spojrzenie na EmguCV &#8211; rysowanie</title>
		<link>https://szogun1987.pl/show/amatorskie-spojrzenie-na-emgucv-rysowanie/23/</link>
		
		<dc:creator><![CDATA[szogun1987]]></dc:creator>
		<pubDate>Sat, 21 Jun 2014 16:25:30 +0000</pubDate>
				<category><![CDATA[C Sharp]]></category>
		<category><![CDATA[EmguCV]]></category>
		<guid isPermaLink="false">https://szogun1987.pl/?p=23</guid>

					<description><![CDATA[Zagadnieniem do kt&#243;rego dotarłem w ramach moich eksploracji EmguCV jest rysowanie.&#160;
Podstawowym narzędziem rysującym jest metoda Draw. Metoda ta ma 11 przeciążeń, kt&#243;re osobiście podzieliłbym na 3 grupy: Rysowanie kształt&#243;w, Wyświetlanie tekstu, Rysowanie sekwencji.


]]></description>
										<content:encoded><![CDATA[<p>Zagadnieniem do kt&oacute;rego dotarłem w ramach moich eksploracji EmguCV jest rysowanie.&nbsp;<br />
Podstawowym narzędziem rysującym jest metoda Draw. Metoda ta ma 11 przeciążeń, kt&oacute;re osobiście podzieliłbym na 3 grupy: Rysowanie kształt&oacute;w, Wyświetlanie tekstu, Rysowanie sekwencji.</p>
<h2>Rysowanie kształt&oacute;w:</h2>
<p>Metoda Draw posiada 7 dedykowanych metod przeznaczonych do rysowania podstawowych kształt&oacute;w geometrycznych. Metody te jako pierwszy parametr przyjmują strukturę opisującą kształt oraz 2 dodatkowe parametry: kolor lini, oraz jej grubość. Przy czym grubość 0 lub mniej oznacza wypełnienie kształtu kolorem.</p>
<pre class="prettyprint lang-cs">
	var rect = new System.Drawing.Rectangle(x, y, width, height);
	image.Draw(rect, color, thickness);
</pre>
<p>I w zasadzie jedyne co mogę stwierdzić to fakt, że działa.</p>
<p>Przypadkiem w kt&oacute;rym nie jest już tak r&oacute;żowo jest koło/okrąg ponieważ to coś&nbsp;<br />
<img decoding="async" alt="Okrąg generowany metodą Draw" src="http://static.szogun1987.pl/upload/EmguCV/Draw/Image1.png" style="height:150px; width:150px" /><br />
co powstaje w wyniku wywołania tego kodu:</p>
<pre class="prettyprint lang-cs">
	CircleF c = new CircleF(new PointF(centerX, centerY), radius);
	image.Draw(c, color, thickness);
</pre>
<p>ciężko nazwać okręgiem. Przydałoby się tutaj trochę antialiasingu, niestety klasa Image nie posiada żadnej metody ani właściwości gwarantującej taką funkcjonalność, a więc trzeba kombinować.<br />
Pierwszym obejściem jakie znalazłem było wykorzystanie właściwości Bitmap kt&oacute;ra jest typu System.Drawing.Bitmap. Właściwość ta dla kolor&oacute;w Brg, Brga oraz Gray zwraca wewnętrzną Bitmapę synchronizowaną dwustronnie z zawartością obrazu, dla pozostałych sposob&oacute;w opisu koloru zwracana jest nowa/niesynchronizowana Bitmapa. Podejrzewam że ta właśnie synchronizacja jest przyczyną przegranej Emgu z metodą BitmapData w teście wydajności. &nbsp;</p>
<p>Mając obiekt typu Bitmap możemy wykorzystać całe bogactwo biblioteki GDI+ w tym klasę Graphics. Narysowanie okręgu z antialiasingiem można wykonać takim kodem:</p>
<pre class="prettyprint lang-cs">
	using (var graphics = Graphics.FromImage(image.Bitmap))
	{
		graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
		using (var pen = new Pen(color, thickness))
		{
			graphics.DrawEllipse(pen, x, y, diameter, diameter);
		}
	}
</pre>
<p>a efekt jego działania prezentuje się następująco<br />
<img decoding="async" alt="Okrąg generowany z wykorzystaniem GDI+" src="http://static.szogun1987.pl/upload/EmguCV/Draw/Image2.png" style="height:150px; width:150px" /></p>
<p>Drugim rozwiązaniem jakie udało mi się znaleźć jest użycie klasy cvInvoke. O ile klasa Image jest dobrze przemyślanym proxy do wielu funkcjonalności z OpenCV tak klasa cvInvoke ma na celu zapewnić dostęp do jak największej grupy metod, niekoniecznie trzymając się najlepszych wzorc&oacute;w. Większość (jak nie wszystkie) z metod tej klasy korzysta bezpośrednio z PInvoke, jest pośr&oacute;d nich także metoda cvImage.</p>
<pre class="prettyprint lang-cs">
	var center = new Point(centerX, centerY);
	int radius = dlg.Radius;
	var color = new Bgr(); // Jakiś kolor
	var lineType = Emgu.CV.CvEnum.LINE_TYPE.CV_AA;
	
	CvInvoke.cvCircle(image.Ptr, center, radius, color.MCvScalar, thickness, lineType, 0);
</pre>
<p>Metoda jako pierwszy parametr pobiera wskaźnik, można go znaleźć w klasie Image&lt;,&gt; pod właściwością Ptr, drugim parametrem są wsp&oacute;łrzędne środka okręgu, a kolejnym jego promień.<br />
Czwartym parametrem jest kolor, nie jest to jednak ani liczba opisująca kolor, ani obiekt z grupy kolor&oacute;w tylko coś nazwane MCvScalar, jak widać w powyższym listingu wartość tą można uzyskać z koloru przy pomocy właściwości MCvScalar.&nbsp;<br />
Piątym parametrem jest grubość linii, interpretowana tak samo jak w metodzie Draw, a sz&oacute;stym jej typ. Są 3 typy linii 4-połączeniowa, 8-połączeniowa (używana przez metodę Draw) oraz AntiAliasing. Wyniki metody cvCircle z r&oacute;żną wartością tego parametru (w powiększeniu) przedstawia grafika poniżej.<br />
<img decoding="async" alt="Okręgi generowane metodą z klasy CvInvoke" src="http://static.szogun1987.pl/upload/EmguCV/Draw/Image3.png" style="height:150px; width:450px" /></p>
<p>Organoleptycznie stwierdzam, w tym miejscu błąd w OpenCV ponieważ przy wybraniu opcji 4-połączeniowej wyraźnie widać połączenia po ukosie, kt&oacute;rych nie powinno być.&nbsp;<br />
Ostatnim parametrem jest przesunięcie służące do skalowania wynikowego okręgu jeżeli 1 piksel ma być r&oacute;wny 1 jednostce we wsp&oacute;łrzędnych środka i długości promienia należy ustawić ten parametr na 0.</p>
<h2>Rysowanie napis&oacute;w</h2>
<p>Jak każda biblioteka graficzna EmguCV umożliwia umieszczanie napis&oacute;w na grafice. Sama klasa Image posiada przeciążenie metody Draw kt&oacute;ra jako parametry pobiera:</p>
<ul>
<li>napis kt&oacute;ry ma zostać narysowany</li>
<li>opis czcionki &#8211; struktura zawierająca dane o czcionce</li>
<li>pozycję tekstu</li>
<li>kolor</li>
</ul>
<h2>Rysowanie sekwencji</h2>
<p>Sekwencja (Typ Seq&lt;T&gt;) jest kolekcją pozwalającym przechowywać elementy w spos&oacute;b uporządkowany. Elementy można dodawać na końcu (Metoda Push) albo na początku (PushFront) sekwencji. Sekwencja wymaga wskazania Magazynu (klasa MemStorage).</p>
<pre class="prettyprint lang-cs">
	using (var memStor = new MemStorage())
	{
		var seq = new Seq(memStor);
		var rand = new Random();
		for (int i = 0; i &lt; 100; i++)
		{
			var point = new Point(rand.Next(100), rand.Next(100));
			seq.Push(point);
		}
	}
</pre>
<p>Metoda Draw posiada 3 metody do rysowania sekwencji punkt&oacute;w. W najprostrzym przypadku przyjmuje ona 3 parametry: wspomnianą sekwencję oraz grubość i kolor linii. Dwa ostatnie parametry są interpretowane analogicznie jak we wczesniejszych przeciążeniach. Co ciekawe przekazanie obiektu Seq&lt;Point&gt; wypełnionymi punktami sprawi, że grafika nie ulegnie zmianie (WTF?).<br />
Po wczytaniu się w dokumentację znalazłem przyczynę. Sekwencja sama w sobie stanowi tylko abstrakcję dla innych implementacji. Jednak jako taka nie jest abstrakcyjna można ją tworzyć, można do niej dodawać elementy, jednak nie da się jej narysować. Kolejną ciekawostką jest fakt iż jedyną klasą dziedziczącą po sekwencji jest Contour&lt;T&gt;, a pr&oacute;ba dziedziczenia i nadpisania jedynej wirtualnej metody InContour nic nie zmienia (podczas rysowania ta metoda nie jest nawet wywoływana). Na szczęście &nbsp;użycie klasy Contour&lt;T&gt; daje efekt w postaci narysowania wielokąta. Kt&oacute;rego wierzchołkami są punkty sekwencji.&nbsp;</p>
<h2>DrawPolyline</h2>
<p>Jak sama nazwa wskazuje służy do rysowania wielu linii, czyli łamanej. Posiada 2 przeciążenia. Pierwsze z nich pobiera jako parametr tablicę punkt&oacute;w, flagę określającą czy domknąć łamaną (czyli zrobić z niej wielokąt), oraz kolor i grubość linii interpretowane tak samo jak przez metodę Draw. Z punktu widzenia programisty można tą metodę traktować jak uproszczoną wersję rysowania konturu.<br />
Drugie przeciążenie r&oacute;żni się pierwszym parametrem jako kt&oacute;ry przyjmuje tablicę tablic punkt&oacute;w &nbsp;i służy do rysowania wielu łamanych.</p>
<h2>FillConvexPolygon</h2>
<p>Metoda pozwala wypełnić kolorem wielokąt wypukły nie należy jednak używać tej metody do rysowania wielokąt&oacute;w wklęsłych albo figur z przecinającymi się krawędziami, metoda ta prawdopodobnie wykorzystuje algorytm skanowania linii (o ile dobrze pamiętam nazwę) wydajny ale ograniczony funkcjonalnie. Moim zdaniem metoda ta ma wąskie zastosowanie.</p>
<p>Przykładowe listingi prezentujące wykorzystanie metod jak &nbsp;zawsze znajdują się w projekcie <a href="https://github.com/szogun1987/EmguExperriments/tree/master/EmguExperiments/Draw">EmguExperiments</a></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Amatorskie spojrzenie na EmguCV &#8211; operacja na pikselach oraz wydajność</title>
		<link>https://szogun1987.pl/show/amatorskie-spojrzenie-na-emgucv-operacja-na-pikselach-oraz-wydajnosc/22/</link>
		
		<dc:creator><![CDATA[szogun1987]]></dc:creator>
		<pubDate>Mon, 16 Jun 2014 20:46:33 +0000</pubDate>
				<category><![CDATA[C Sharp]]></category>
		<category><![CDATA[EmguCV]]></category>
		<guid isPermaLink="false">https://szogun1987.pl/?p=22</guid>

					<description><![CDATA[Pomimo bardzo bogatego zestawu metod klasy Image nie robi ona wszystkiego. Więc istnieje konieczność operacji bezpośrednio na punktach&#160;składających się na obraz.

]]></description>
										<content:encoded><![CDATA[<p>Pomimo bardzo bogatego zestawu metod klasy Image nie robi ona wszystkiego. Więc istnieje konieczność operacji bezpośrednio na punktach składających się na obraz. EmguCV oferuje dwie możliwości:</p>
<li>
<p>Czytelną w kt&oacute;rej zostaje użyty indekser zwracający obiekt TColor(w przykładzie poniżej Bgr)</p>
<pre class="prettyprint lang-cs">
var pixel = image[row, column];
pixel.B = value;
image[row, column] = pixel;
</pre>
</li>
<li>
<p> Mniej czytelną ale wydajnieszą, odwołanie następuje do obiektu Data indekser na nim pozwala pominąć operacje na obiekcie i operować bezpośrednio na tablicy znajdującej się pod spodem.</p>
<pre class="prettyprint lang-cs">
byte bluePartOfPixel = image.Data[row, column, 0];
image.Data[row, column, 0] = (byte)78;
</pre>
</li>
</ul>
<p>Najwyższa pora sprawdzić wydajność Emgu CV. Postanowiłem zaimplementować metodę generującą negatyw zdjęcia na kilka sposob&oacute;w:</p>
<ul>
<li>GetPixel/SetPixel &#8211; metoda z g&oacute;ry skazana na przegraną, jej jedynymi zaletami są: nie zła czytelność kodu, oraz fakt że dostępna w .Net z pudełka</li>
<li>BitmapData &#8211; wydajna metoda, gł&oacute;wny konkurent Emgu CV pod tym względem, opr&oacute;cz wydajności posiada same wady: wymaga używania sekcji unsafe, jest mało czytelna i błędogenna. Ze względu na ostatnią cechę zamiast się bawić w ręczną implementację wykorzystałem gotowca ze <a href="http://stackoverflow.com/questions/541331/effective-way-of-making-negative-of-image-without-external-dlls">Stacka</a></li>
<li>ColorMatrix &#8211; stare dobre GDI+ umożliwia dokonywania przekształceń matrycowych zar&oacute;wno na orientacji pikseli jak i ich kolor&oacute;w (potrzebna jest do tego klasa Graphics) implementację znalazłem pod tym samym linkiem, co w przypadku BitmapData</li>
<li>Pixel Access pierwsza wspomniana w tym poście metoda dostęp&oacute;w do pikseli w EmguCV</li>
<li>Pixel Access Fast &#8211; druga metoda</li>
<li>Metoda Not &#8211; metoda w klasie Image dedykowana generowaniu negatywu obrazu</li>
</ul>
<p>Testy wykonywałem na swoim laptopie (8 GB RAM, i5, dwie karty grafiki NVidia NVS 5400M oraz jakiś Intel). Test podzieliłem na 2 kroki Otwarcie pliku &#8211; polegające na wywołaniu konstruktora klasy z odpowiednim parametrem, oraz Wygenerowanie negatywu &#8211; właściwa robota. Odrzucałem wynik pierwszego uruchomienia Testu (podczas niego mogą wykonywać się operacje kt&oacute;re nie występują przy kolejnych uruchomieniach). Test wykonałem tylko na trzech plikach, oraz uruchamiając program na r&oacute;żnych kartach grafiki (mam możliwość wskazania kt&oacute;ra karta powinna być wykorzystana).<br />
Metoda badań nie jest może idealna jednak mimo to daje całkiem ciekawe wyniki:</p>
<p>Obraz 3702&#215;2304 jpeg 916KB</p>
<p>NVidia NVS 5400M</p>
<table class="table">
<thead>
<tr>
<th></th>
<th colspan="3">GDI+</th>
<th colspan="3">Emgu CV</th>
</tr>
<tr>
<th>Metoda</th>
<th>GetPixel/SetPixel</th>
<th>BitmapData</th>
<th>ColorMatrix</th>
<th>Pixel Access</th>
<th>Pixel Access Fast</th>
<th>Metoda Not</th>
</tr>
</thead>
<tbody>
<tr>
<th>Otwarcie pliku</th>
<td>00.037</td>
<td>00.038</td>
<td>00.039</td>
<td>00.107</td>
<td>00.110</td>
<td>00.112</td>
</tr>
<tr>
<th>Wygenerowanie negatywu</th>
<td>10.404</td>
<td>00.054</td>
<td>00.157</td>
<td>02.892</td>
<td>02.088</td>
<td>00.114</td>
</tr>
</tbody>
</table>
<p>Intel(R) HD Graphics 4000</p>
<table class="table">
<thead>
<tr>
<th></th>
<th colspan="3">GDI+</th>
<th colspan="3">Emgu CV</th>
</tr>
<tr>
<th>Metoda</th>
<th>GetPixel/SetPixel</th>
<th>BitmapData</th>
<th>ColorMatrix</th>
<th>Pixel Access</th>
<th>Pixel Access Fast</th>
<th>Metoda Not</th>
</tr>
</thead>
<tbody>
<tr>
<th>Otwarcie pliku</th>
<td>00.037</td>
<td>00.036</td>
<td>00.038</td>
<td>00.110</td>
<td>00.113</td>
<td>00.110</td>
</tr>
<tr>
<th>Wygenerowanie negatywu</th>
<td>10.470</td>
<td>00.053</td>
<td>00.157</td>
<td>03.071</td>
<td>02.296</td>
<td>00.112</td>
</tr>
</tbody>
</table>
<p>Obraz 4320&#215;3240 jpeg 3,21 MB</p>
<p>NVidia NVS 5400M</p>
<table class="table">
<thead>
<tr>
<th></th>
<th colspan="3">GDI+</th>
<th colspan="3">Emgu CV</th>
</tr>
<tr>
<th>Metoda</th>
<th>GetPixel/SetPixel</th>
<th>BitmapData</th>
<th>ColorMatrix</th>
<th>Pixel Access</th>
<th>Pixel Access Fast</th>
<th>Metoda Not</th>
</tr>
</thead>
<tbody>
<tr>
<th>Otwarcie pliku</th>
<td>00.037</td>
<td>00.038</td>
<td>00.039</td>
<td>00.107</td>
<td>00.110</td>
<td>00.112</td>
</tr>
<tr>
<th>Wygenerowanie negatywu</th>
<td>20.764</td>
<td>00.118</td>
<td>00.340</td>
<td>06.079</td>
<td>04.302</td>
<td>00.252</td>
</tr>
</tbody>
</table>
<p>Intel(R) HD Graphics 4000</p>
<table class="table">
<thead>
<tr>
<th></th>
<th colspan="3">GDI+</th>
<th colspan="3">Emgu CV</th>
</tr>
<tr>
<th>Metoda</th>
<th>GetPixel/SetPixel</th>
<th>BitmapData</th>
<th>ColorMatrix</th>
<th>Pixel Access</th>
<th>Pixel Access Fast</th>
<th>Metoda Not</th>
</tr>
</thead>
<tbody>
<tr>
<th>Otwarcie pliku</th>
<td>00.088</td>
<td>00.087</td>
<td>00.086</td>
<td>00.248</td>
<td>00.244</td>
<td>00.247</td>
</tr>
<tr>
<th>Wygenerowanie negatywu</th>
<td>20.644</td>
<td>00.120</td>
<td>00.344</td>
<td>06.041</td>
<td>04.066</td>
<td>00.252</td>
</tr>
</tbody>
</table>
<p>Obraz 5184&#215;3456 jpeg 4,87 MB</p>
<p>NVidia NVS 5400M</p>
<table class="table">
<thead>
<tr>
<th></th>
<th colspan="3">GDI+</th>
<th colspan="3">Emgu CV</th>
</tr>
<tr>
<th>Metoda</th>
<th>GetPixel/SetPixel</th>
<th>BitmapData</th>
<th>ColorMatrix</th>
<th>Pixel Access</th>
<th>Pixel Access Fast</th>
<th>Metoda Not</th>
</tr>
</thead>
<tbody>
<tr>
<th>Otwarcie pliku</th>
<td>00:00.112</td>
<td>00:00.117</td>
<td>00:00.115</td>
<td>00:00.345</td>
<td>00:00.353</td>
<td>00:00.355</td>
</tr>
<tr>
<th>Wygenerowanie negatywu</th>
<td>00:00.112</td>
<td>00:00.117</td>
<td>00:00.115</td>
<td>00:00.345</td>
<td>00:00.353</td>
<td>00:00.355</td>
</tr>
</tbody>
</table>
<p>Intel(R) HD Graphics 4000</p>
<table class="table">
<thead>
<tr>
<th></th>
<th colspan="3">GDI+</th>
<th colspan="3">Emgu CV</th>
</tr>
<tr>
<th>Metoda</th>
<th>GetPixel/SetPixel</th>
<th>BitmapData</th>
<th>ColorMatrix</th>
<th>Pixel Access</th>
<th>Pixel Access Fast</th>
<th>Metoda Not</th>
</tr>
</thead>
<tbody>
<tr>
<th>Otwarcie pliku</th>
<td>00:00.114</td>
<td>00:00.119</td>
<td>00:00.118</td>
<td>00:00.348</td>
<td>00:00.351</td>
<td>00:00.342</td>
</tr>
<tr>
<th>Wygenerowanie negatywu</th>
<td>00:00.114</td>
<td>00:00.119</td>
<td>00:00.118</td>
<td>00:00.348</td>
<td>00:00.351</td>
<td>00:00.342</td>
</tr>
</tbody>
</table>
<p>Zgodnie z moimi oczekiwaniami BitmapData pokonał inne metody GDI+. Wywołanie dedykowanej metody Not detronizuje zabawę bezpośrednio na Pikselach, jak dla mnie jest to jednoznaczne ze stwierdzeniem &quot;Jak coś jest już napisane nie pisz tego sam&quot;.<br />
Bardzo interesujący natomiast jest fakt iż metoda BitmapData jest dwukrotnie szybsza od dedykowanej metody z Emgu CV. Jestem jednak daleki od stwierdzenia iż m&oacute;j test udowadnia słabość tej biblioteki. Wskazany wynik może mieć wiele przyczyn, metoda Not może być na tyle prosta że Emgu CV nie ma co optymalizować (na co wskazywałby brak istotnych r&oacute;żnic przy uruchamianiu programu na r&oacute;żnych kartach grafiki), jednak ambitniejszych przekształceń po prostu nie chce mi się implementować &quot;z palca&quot; więc nie dokonam takiego por&oacute;wnania.<br />
Warto też zwr&oacute;cić uwagę na fakt iż przekształcenie matrycowe także nie wypadło źle w zestawieniu, a jego czytelność jest przyzwoita (co nie zmienia faktu iż kod pisany z jego wykorzystaniem zawsze powinien być komentowany).<br />
Ostatnim elementem układanki jest czas pobrania danych z dysku. W przypadku Emgu CV odczytanie danych stanowi dużą część pracochłonności całej operacji. W moim teście popełniłem jeden błąd i większe zdjęcia wczytywałem z dysku SSD, a małe z talerzowego więc nie może on być podstawą wnioskowania o skalowalności tego rozwiązania.<br />
Całość kodu testu znajduje się pod adresem: <a href="https://github.com/szogun1987/EmguExperriments/tree/master/EmguExperiments/Performance">https://github.com/szogun1987/EmguExperriments/tree/master/EmguExperiments/Performance</a></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Amatorskie spojrzenie na EmguCV &#8211; podstawowe przekształcenia obrazów</title>
		<link>https://szogun1987.pl/show/amatorskie-spojrzenie-na-emgucv-podstawowe-przeksztalcenia-obrazow/21/</link>
		
		<dc:creator><![CDATA[szogun1987]]></dc:creator>
		<pubDate>Sun, 15 Jun 2014 14:01:34 +0000</pubDate>
				<category><![CDATA[C Sharp]]></category>
		<category><![CDATA[EmguCV]]></category>
		<guid isPermaLink="false">https://szogun1987.pl/?p=21</guid>

					<description><![CDATA[W trzeciej części serii chciałbym ukazać łatwość z jaką przy pomocy EmguCV można dokonywać przekształceń obrazu. W tym poście skoncentruję się na 3 przekształceniach: Odbicie lustrzane (Flip), Obrocie, Skalowaniu.

]]></description>
										<content:encoded><![CDATA[<p>W trzeciej części serii chciałbym ukazać łatwość z jaką przy pomocy EmguCV można dokonywać przekształceń obrazu. W tym poście skoncentruję się na 3 przekształceniach: Odbicie lustrzane (Flip), Obrocie, Skalowaniu.<br />
Jednak zanim przejdę do właściwego tematu chciałbym wspomnieć o ręcznym zarządzaniu zasobami. Klasa Image&lt;TColor, TDepth&gt; implementuje interfejs IDisposable co wskazuje na konieczność zwalniania zasob&oacute;w gdy tylko obiekt przestaje nam być potrzebny. Jednak dokumentacja Emgu m&oacute;wi o braku takiej konieczności (prawdopodobnie jest to związane z faktem iż Emgu poprawnie implementuje ten interfejs a sama klasa posiada finalizer zwalniający zasoby gdy przyjdzie odpowiednia pora. Ja osobiście domyślnie wywołuję Dispose (czy to jawnie czy to przez konstrukcję using), chyba że mam wątpliwości czy zwalniany obiekt nie jest gdzieś jeszcze używany, dlatego w swoim projekciku raczej nie będę się stosował do zaleceń dostawcy.<br />
&nbsp;<br />
Aby zrobić odbicie lustrzane obrazu należy na nim wywołać metodę Flip (albo _Flip), metoda ta jako parametr pobiera wartość FLIP.HORIZONTAL albo FLIP.VERTICAL gdzie FLIP jest Enum&#39;em.<br />
Przy okazji wr&oacute;cę do tematu metod &quot;podreślnikowych&quot;. Kilka moich eksperyment&oacute;w potwierdziło że ich używanie zużywa mniej pamięci operacyjnej niż używanie ich odpowiednik&oacute;w bez podkreślnika na początku. Drugim spostrzeżeniem jakiego przy ich okazji dokonałem to fakt iż kontrolka ImageBox nie obserwuje zmian w obrazie i po wywołaniu metody z podkreślnikiem należy albo podstawić właściwość Image kontrolki ponownie albo wywołać na niej Invalidate.&nbsp;<br />
Wadą API Emgu CV jaką widać na przykładzie metod podkreślnikowych i ww. enuma jest nie trzymanie się konwencji nazewniczych przyjętych w C#.<br />
Jednak odbicie lustrzane nie jest niczym nadzwyczajnym (nawet klasa System.Drawing.Bitmap posiada metodę RotateFlip), dlatego przechodzę do czegoś co w Windows Forms jest gorzej wspierane, a więc obr&oacute;t. W Emgu CV dokonuje się go metodą Rotate (jakie zaskakujące), metoda ta nie posiada swojego &quot;podkreślnikowego&quot; odpowiednika prawdopodobnie ze względu na fakt iż zmienia ona rozmiar obrazu. Metoda ta posiada 3 przeciążenia w najprostrzym przypadku parametrami tej metody jest kąt obrotu w stopniach oraz kolor jakim zostaną wypełnione &quot;dziury&quot; w obrazie powstałe w wyniku niedopasowania, dodatkowo można zdefiniować czy wynikowy obraz ma być obcięty do oryginalnych rozmiar&oacute;w (domyślnie obraz jest obcięty), środek obrotu &#8211; punkt niestety nie udało mi się ustalić sposobu jego interpretacji, a w dokumentacji kt&oacute;rą znalazłem brakowało opisu tego przeciążenia metody Rotate. Ostatnim parametrem jest spos&oacute;b interpolacji &#8211; pomijając obroty o wielokrotności 90 stopni jasnym jest że po obrocie piksele oryginalnego obrazu nie trafią idealnie w piksele obrazu wynikowego, więc kolory pikseli wynikowych należy obliczyć na podstawie kolor&oacute;w pikseli kt&oacute;re wylądowały w pobliżu. W zastosowaniach profesjonalnych może parametr ten może mieć znaczenie, jednak organoleptycznie nie udało mi się dostrzec r&oacute;żnic pomiędzy wynikami zastosowanymi z r&oacute;żnymi wynikami tego parametru.<br />
Skalowanie obrazu wykonuje się przy pomocy metody Resize. Posiada ona 3 przeciążenia, wszystkie 3 mają parametr interpolationType interpretowany analogicznie jak taki sam parametr w obrocie. Najprostrze przeciążenie przyjmuje opr&oacute;cz tego parametru także skalę. Drugie przeciążenie zamiast skali przyjmuje docelową szerokość i wysokość obrazu &#8211; przy czym obraz może się skalować inaczej wzdł&oacute;ż osi X, a inaczej wzdł&oacute;ż osi Y. Ostatnie przeciążenie do drugiego przeciążenia dodaje parametr preserveScale ustawienie go na true sprawi że obraz zostanie zeskalowany tak aby się zmieścił w docelowym prostokącie, nic z obrazu nie zostało obcięte oraz bez naruszenia proporcji, to przeciążenie świetnie się nadaje do generowania miniaturek (ponieważ takie warunki muszą one zazwyczaj spełnić.<br />
Na koniec dodam że moim celem nie jest opisywanie na łamach tego bloga wszystkich element&oacute;w EmguCV &#8211; nie chcę powielać dokumentacji.<br />
Przykładowy kod wykorzystujący ww metody znajduje się <a href="https://github.com/szogun1987/EmguExperriments/tree/master/EmguExperiments/BasicTransformations">Tutaj&nbsp;</a></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Amatorskie spojrzenie na EmguCv &#8211; kontrolka Image Box</title>
		<link>https://szogun1987.pl/show/amatorskie-spojrzenie-na-emgucv-kontrolka-image-box/20/</link>
		
		<dc:creator><![CDATA[szogun1987]]></dc:creator>
		<pubDate>Sat, 14 Jun 2014 12:39:01 +0000</pubDate>
				<category><![CDATA[C Sharp]]></category>
		<category><![CDATA[EmguCV]]></category>
		<guid isPermaLink="false">https://szogun1987.pl/?p=20</guid>

					<description><![CDATA[W poprzednim wpisie wspomniałem o metodzie ToBitmap klasy Image pozwalającej na konwersję klasy Image na klasę System.Drawing.Bitmap, co pozwala na używanie wyniku obr&#243;bki obrazu w kontrolkach Windows Forms. Jednak taka konwersja nie należy do najszybszych operacji, po za tym powoduje zwiększenie zużycia pamięci, ponieważ obraz jest przechowywany w pamięci w dw&#243;ch postaciach. Ponieważ najczęstszym zastosowaniem obraz&#243;w jest ich wyświetlanie do EmguCV została dodana kontrolka ImageBox.

]]></description>
										<content:encoded><![CDATA[<p>W poprzednim wpisie wspomniałem o metodzie ToBitmap klasy Image pozwalającej na konwersję klasy Image na klasę System.Drawing.Bitmap, co pozwala na używanie wyniku obr&oacute;bki obrazu w kontrolkach Windows Forms. Jednak taka konwersja nie należy do najszybszych operacji, po za tym powoduje zwiększenie zużycia pamięci, ponieważ obraz jest przechowywany w pamięci w dw&oacute;ch postaciach. Ponieważ najczęstszym zastosowaniem obraz&oacute;w jest ich wyświetlanie do EmguCV została dodana kontrolka ImageBox.</p>
<p>Jest ona pod pewnymi względami podobna do PictureBox z WindowsForms, podstawową r&oacute;żnicą jest fakt iż jako źr&oacute;dła używa klasy IImage (po kt&oacute;rym dziedziczy Image&lt;TColor, TDepth&gt;) , a nie Bitmap. Kontrolka ta dodaje też kilka funkcjonalności np. skalowanie obrazka myszką, obsługę rolki itp. jednak mam nadzieję że da się to wyłączyć <a href="#Edit">Edit</a>.</p>
<p>Aby dodać kontrolkę ImageBox do projektu należy dodać referencję do EmguCV (operację tą opisałem w poprzednim poście) i to wystarczy aby używać tej kontrolki z poziomu kodu. Jednak aby ww. kontrolka pojawiła się także w toolboxie należy się jeszcze trochę wysilić.</p>
<p>Po kliknięciu prawym przyciskiem myszy w wolny obszar na toolboxie należy wybrać&ldquo;Add Tab&rdquo; ja swoją zakładkę nazwałem &ldquo;EmguControls&rdquo;:</p>
<p><img decoding="async" alt="AddTab" src="http://static.szogun1987.pl/upload/EmguCV/ImageBox/Part1.png" style="height:403px; width:365px" /></p>
<p>Następnie należy kliknąć prawym przyciskiem myszy w nową zakładkę wybrać opcję &ldquo;Choose Items&rdquo;.</p>
<p><img decoding="async" alt="Choose Items" src="http://static.szogun1987.pl/upload/EmguCV/ImageBox/Part2.png" style="height:321px; width:341px" /></p>
<p>Na wyświetlonym oknie można należy wybrać przycisk &ldquo;Browse&rdquo;, wskazać ścieżkę do EmguCV.UI.dll i zatwierdzamy obydwa formularze.</p>
<p><img decoding="async" alt="Browse" src="http://static.szogun1987.pl/upload/EmguCV/ImageBox/Part3.png" style="height:502px; width:698px" /></p>
<p>Opr&oacute;cz kontrolki ImageBox zostają też dodane też kontrolki HistogramBox, MatrixBox, PanAndZoomPictureBox ich eksploracją zajmę się w p&oacute;źniejszym czasie (o ile mi starczy chęci).</p>
<p>Na koniec dodam iż eksplorację EmguCV będę dodatkowo dokumentował na GitHubie w projekcie <a href="https://github.com/szogun1987/EmguExperriments">https://github.com/szogun1987/EmguExperriments</a></p>
<p>W projekcie brakuje bibliotek OpenCV ze względu na ich rozmiar, należy je sobie samemu podlinkować/skopiować.</p>
<p>Ponieważ projekt ma za zadanie ukazać możliwości API w jak najprostrzy spos&oacute;b większość kodu będzie się znajdowała w EventHandlerach (nie znam dobrego polskiego odpowiednika tego słowa), a sam kod będzie pełen powt&oacute;rzeń. Więc nie uznaję krytyki tych aspekt&oacute;w. Natomiast chętnie zapoznam się z innymi uwagami.</p>
<p><a id="Edit" name="Edit"></a></p>
<p><strong style="line-height:1.6">Edit:</strong></p>
<p>Właściwością kontrolki determinującą zachowanie kontrolki jest FunctionalMode. Właściwość ta może przyjmować 4 wartości:</p>
<ul>
<li>Minimum &#8211; ogranicza się do wyświetlenia obrazka ta na kt&oacute;rej mi zależy.</li>
<li>RightClickMenu &#8211; wyświetla menu pozwalające na dokonywanie przekształceń na obrazie, ponieważ Menu pokrywa większość funkcjonalności projektu EmguExperiments wyłącze je w swoim projekcie</li>
<li>PanAndZoom &#8211; obsługa gest&oacute;w myszy</li>
<li>Everything &#8211; jak sama nazwa wskazuje wszystkie funkcjonalności &#8211; wartość domyślna dla właściwości FunctionalMode</li>
</ul>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Amatorskie spojrzenie na EmguCV</title>
		<link>https://szogun1987.pl/show/amatorskie-spojrzenie-na-emgucv/19/</link>
		
		<dc:creator><![CDATA[szogun1987]]></dc:creator>
		<pubDate>Tue, 10 Jun 2014 20:43:35 +0000</pubDate>
				<category><![CDATA[C Sharp]]></category>
		<category><![CDATA[EmguCV]]></category>
		<category><![CDATA[Programowanie]]></category>
		<guid isPermaLink="false">https://szogun1987.pl/?p=19</guid>

					<description><![CDATA[EmguCV jest .Netowym wrapperem do OpenCV - potężnej biblioteki do przetwarzania i analizy obraz&#243;w (zar&#243;wno statycznych jak i ruchomych) oraz innych sygnał&#243;w cyfrowych.



Ważną cechą biblioteki jest fakt iż stara się ona wykorzystać jak najlepiej zasoby dostępne na maszynie na kt&#243;rej jest ona uruchomiona, ze szczeg&#243;lnym uwzględnieniem karty grafiki.

]]></description>
										<content:encoded><![CDATA[<p>EmguCV jest .Netowym wrapperem do OpenCV &#8211; potężnej biblioteki do przetwarzania i analizy obraz&oacute;w (zar&oacute;wno statycznych jak i ruchomych) oraz innych sygnał&oacute;w cyfrowych.</p>
<p>Ważną cechą biblioteki jest fakt iż stara się ona wykorzystać jak najlepiej zasoby dostępne na maszynie na kt&oacute;rej jest ona uruchomiona, ze szczeg&oacute;lnym uwzględnieniem karty grafiki.</p>
<p>Opr&oacute;cz tego OpenCV wspiera machine learning, jednak tej części biblioteki jeszcze nie dotykałem.</p>
<p>Co ma wsp&oacute;lnego programista .Net zajmujący się nudnymi dokumentami korporacyjnymi z przetwarzaniem obraz&oacute;w? Niewiele. Po prostu od czasu do czasu trzeba spr&oacute;bować czegoś nowego for-fun więc znalazłem pierwszy lepszy pretekst żeby pobawić się się EmguCV.</p>
<p>Od razu zaznaczę, że nie czytałem o żadnych dobrych praktykach, ani nawet nie zagłębiałem się w tutoriale tylko postanowiłem rozpocząć naukę przez eksplorację wspartą przez google i stackoverflow. W dodatku skoncentrowałem się tylko na podstawowych przekształceniach obraz&oacute;w statycznych.</p>
<h1>1. Instalacja</h1>
<p>Instalację należy zacząć od wejścia na stronę <a href="http://sourceforge.net/projects/emgucv/">http://sourceforge.net/projects/emgucv/</a> i pobrania instalatora i klikania next, next, next. Już sam rozmiar paczki instalacyjnej robi wrażenie (200+MB), Natomiast po jej zainstalowaniu stracimy prawie 2GB dysku. Liczbę tą można zmniejszyć rezygnując z instalacji przykładowych solucji.</p>
<h1>2. Pierwsze podpięcie</h1>
<p>Podłączenie Emgu do solucji w celu przekształcania obraz&oacute;w statycznych jest opisane na stronie <a href="http://www.emgu.com/wiki/index.php/Setting_up_EMGU_C_Sharp">http://www.emgu.com/wiki/index.php/Setting_up_EMGU_C_Sharp</a> zgodnie z tym tutorialem należy do swojego projektu dodać referencje do dll&rsquo;ek EmguCV.dll, EmguCV.UI.dll oraz EmguCV.Util.dll biblioteki te znajdują się w katalogu &ldquo;&lt;ścieżka_do_emgu&gt;\bin&rdquo;.</p>
<p>Biblioteki te nie są jednak samodzielnymi bibliotekami tylko wrapperami do bibliotek napisanych w c++ kt&oacute;re posiadają wersje 32 i 64 bitową co za tym idzie nasza aplikacja albo będzie miała 2 wersje albo nie będzie działać na niekt&oacute;rych stacjach roboczych.</p>
<p>Powoduje to że powinniśmy ustawić właściwość &ldquo;Target platform&rdquo; na &ldquo;x64&rdquo; (Properties w naszym csproj, zakładka Build).</p>
<p>Drugim problemem o kt&oacute;rym wspomniany wcześniej tutorial nie m&oacute;wi to fakt iż zależności między bibliotekami się trochę pozmieniały i dodanie do projektu tylko i wyłącznie opencv_core&lt;ver&gt;.dll i opencv_imgproc&lt;ver&gt;.dll (znajdujacych się w katalogu &nbsp;&ldquo;&lt;ścieżka_do_emgu&gt;\bin\x64&rdquo;) sprawi że po wykorzystaniu jakiejkolwiek metody z biblioteki EmguCV dostaniemy w twarz błędem o mało m&oacute;wiącym komunikacie &ldquo;&#39;System.TypeInitializationException&#39; occurred in Emgu.CV.dll&rdquo;. Grzebiąc po internecie znalazłem poradę aby po prostu przekopiować cały katalog &ldquo;&lt;ścieżka_do_emgu&gt;\bin\x64&rdquo; do swojej solucji tak aby lądował w katalogu bin\Debug wadą tego rozwiązania jest jednak fakt iż cały katalog waży 566MB. Jeżeli ktoś zna minimalny podzbi&oacute;r dll&rsquo;ek potrzebny do otworzenia obrazu z pliku i wyświetlenia go w Picturebox będę wdzięczny.</p>
<h1>3. Pokaż cy&hellip;kod</h1>
<p>Podstawową klasą z kt&oacute;rej korzystałem podczas moich zabaw jest Image&lt;TColor, TDepth&gt; jak widać jest to klasa generyczna pierwszy parametr oznacza w jaki spos&oacute;b można operować na kolorach obrazu. Przykładami typ&oacute;w kt&oacute;re można tam postawić są Bgr, Gray, Bgr556, Hsv i kilka innych. Parametr TDepth oznacza typ używany do określenia głębi kolor&oacute;w (osobiście zawsze tam wrzucam byte).</p>
<p>Klasa ta posiada kilka kontruktor&oacute;w z kt&oacute;rych według mnie najważniejsze to:</p>
<p>public Image(Bitmap bmp);</p>
<p>Służy do konwesji bitmapy z przestrzeni nazw System.Drawing na obraz kt&oacute;ry nadaje się do przetworzenia przez Emgu.</p>
<pre class="prettyprint lang-cs">public Image(string fileName)</pre>
<p>Pozwala otworzyć obraz z pliku, metoda nie wspiera format&oacute;w Uri, jednak wnioskując po treści zgłaszanego wyjątku obsługa taka zostanie dodana</p>
<pre class="prettyprint lang-cs">public Image(int width, int height, TColor value);</pre>
<p>Tworzy obraz o zadanych wymiarach i kolorze</p>
<p>Niestety pośr&oacute;d konstruktor&oacute;w brakuje otwarcia obrazu z dowolnego strumienia, jednak można się posiłkować następującym obejściem:</p>
<pre class="prettyprint lang-cs">
using (Stream stream = new SomeStream())
            {
                using (var memoryStream = new MemoryStream())
                {
                    stream.CopyTo(memoryStream);
                    memoryStream.Position = 0;

                    Image<Bgr, byte> image = Image<Bgr, byte>.FromRawImageData(memoryStream.ToArray());
                }
            }

</pre>
<p>Klasa Image zawiera szereg metod kt&oacute;re można podzielić na dwie grupy:</p>
<ul>
<li>
<p>zaczynające się od podkreślenia &#8211; zmieniają obiekt obrazu na kt&oacute;rym są wywoływane</p>
</li>
<li>
<p>nazywające się jak pan B&oacute;g przykazał &#8211; generują kopię obrazu z naniesionymi zmianami</p>
</li>
</ul>
<p>Część metod posiada wersję z podkreśleniem i bez. Intuicja mi podpowiada że metody &ldquo;podkreślnikowe&rdquo; są wydajniejsze ale nie są nie można ich używać bezpiecznie w środowisku wielowątkowym (nie szukałem jednak potwierdzenia tej tezy w dokumentacji).</p>
<p>Pierwszą metodą w klasie Image, kt&oacute;rą postanowiłem przybliżyć jest Convert&lt;TColor, TDepth&gt; &nbsp;metoda da pozwala na stworzenie obrazu opisanego w inny spos&oacute;b lub mającego inną głębię.</p>
<pre class="prettyprint lang-cs">
// Dzięki temu możemy operować na głębi i nasyceniu kolor&oacute;w
var image2 = image.Convert&lt;Hsv, byte&gt;();
// Konwersja na skalę szarości - nieodwracalna
var image3 = image.Convert&lt;Gray, byte&gt;();
</pre>
<p>
Drugą ważną dla mnie metodą jest .ToBitmap pozwalająca konwertować obraz do klasy System.Drawing.Bitmap co pozwala wyświetlić wynik przekształceń w kontrolkach Windows Forms.</p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
