<?xml version='1.0' encoding='utf-8' ?>
<!--  If you are running a bot please visit this policy page outlining rules you must respect. http://www.livejournal.com/bots/  -->
<rss version='2.0' xmlns:lj='http://www.livejournal.org/rss/lj/1.0/' xmlns:media='http://search.yahoo.com/mrss/' xmlns:atom10='http://www.w3.org/2005/Atom'>
<channel>
  <title>Блог Ермолаева Игоря</title>
  <link>http://ermig.livejournal.com/</link>
  <description>Блог Ермолаева Игоря - LiveJournal.com</description>
  <lastBuildDate>Mon, 09 Apr 2012 12:23:57 GMT</lastBuildDate>
  <generator>LiveJournal / LiveJournal.com</generator>
  <lj:journal>ermig</lj:journal>
  <lj:journalid>11307901</lj:journalid>
  <lj:journaltype>personal</lj:journaltype>
  <atom10:link rel='hub' href='http://pubsubhubbub.appspot.com/' />
  <image>
    <url>http://l-userpic.livejournal.com/93837931/11307901</url>
    <title>Блог Ермолаева Игоря</title>
    <link>http://ermig.livejournal.com/</link>
    <width>100</width>
    <height>100</height>
  </image>

<item>
  <guid isPermaLink='true'>http://ermig.livejournal.com/170764.html</guid>
  <pubDate>Mon, 09 Apr 2012 12:23:57 GMT</pubDate>
  <title>Чудесная идея</title>
  <link>http://ermig.livejournal.com/170764.html</link>
  <description>Я чудесную идею&lt;br /&gt;Ясно вижу без препон:&lt;br /&gt;Как на сайте в интернете&lt;br /&gt;Заработать миллион!&lt;br /&gt;&lt;br /&gt;Лишь одна осталось малость,&lt;br /&gt;Если можно так сказать:&lt;br /&gt;Нужно мне мою идею&lt;br /&gt;Поскорей реализовать!&lt;br /&gt;&lt;br /&gt;Я инвестор, денег море&lt;br /&gt;У меня уже давно,&lt;br /&gt;Я не жадный, но зарплаты&lt;br /&gt;Не простите все равно!&lt;br /&gt;&lt;br /&gt;И про план я свой секретный&lt;br /&gt;Ничего вам не скажу...&lt;br /&gt;Поработайте бесплатно,&lt;br /&gt;Может после награжу!&lt;br /&gt;&lt;br /&gt;Если все пойдет нормально&lt;br /&gt;И рак свистнет на горе,&lt;br /&gt;Пол процента своей доли&lt;br /&gt;Так и быть отдам тебе!</description>
  <comments>http://ermig.livejournal.com/170764.html</comments>
  <lj:security>public</lj:security>
  <lj:reply-count>2</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://ermig.livejournal.com/170498.html</guid>
  <pubDate>Mon, 06 Feb 2012 08:55:33 GMT</pubDate>
  <title>Потеплело за окошком</title>
  <link>http://ermig.livejournal.com/170498.html</link>
  <description>Потеплело за окошком,&lt;br /&gt;Курс рубля рекорд побил -&lt;br /&gt;Вот что значит Лукашенко&lt;br /&gt;К нам из отпуска прибыл!</description>
  <comments>http://ermig.livejournal.com/170498.html</comments>
  <lj:security>public</lj:security>
  <lj:reply-count>3</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://ermig.livejournal.com/170317.html</guid>
  <pubDate>Thu, 26 Jan 2012 05:56:09 GMT</pubDate>
  <title>Былое вдохновение</title>
  <link>http://ermig.livejournal.com/170317.html</link>
  <description>Утеряно былое вдохновение,&lt;br /&gt;А то бы здесь уже давно&lt;br /&gt;Я безо всякого стеснения&lt;br /&gt;Поэму выдал про говно.</description>
  <comments>http://ermig.livejournal.com/170317.html</comments>
  <lj:security>public</lj:security>
  <lj:reply-count>5</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://ermig.livejournal.com/170122.html</guid>
  <pubDate>Mon, 28 Nov 2011 08:26:08 GMT</pubDate>
  <title>Радиоактивные отходы и Гринпис</title>
  <link>http://ermig.livejournal.com/170122.html</link>
  <description>Поезд едет, а в вагонах&lt;br /&gt;Под тройной стальной броней,&lt;br /&gt;Тихо плещутся отходы&lt;br /&gt;С излучающей &amp;quot;фигней&amp;quot;.&lt;br /&gt;&lt;br /&gt;Охраняют это поезд -&lt;br /&gt;Ведь понятно, что вокруг&lt;br /&gt;не покажется всем мало,&lt;br /&gt;Если что случиться вдруг...&lt;br /&gt;&lt;br /&gt;Но &amp;quot;зеленые&amp;quot; всех больше&lt;br /&gt;Думу думают о том,&lt;br /&gt;Что бы поезд ненароком&lt;br /&gt;Не испачкал ихний дом.&lt;br /&gt;&lt;br /&gt;От того себя на рельсы&lt;br /&gt;Перед поездом кладут,&lt;br /&gt;И отходам ненавистным&lt;br /&gt;Продвигаться не дают.&lt;br /&gt;&lt;br /&gt;А ведь может так случиться:&lt;br /&gt;Кто-то ляжет на пути,&lt;br /&gt;Тормозить придется быстро,&lt;br /&gt;Можно с рельсов и сойти...&lt;br /&gt;&lt;br /&gt;Разольются тут отходы,&lt;br /&gt;И начнется страшный гам...&lt;br /&gt;А Гринпис всем гордо скажет:&lt;br /&gt;&amp;quot;А ведь я предупреждал!&amp;quot;</description>
  <comments>http://ermig.livejournal.com/170122.html</comments>
  <lj:security>public</lj:security>
  <lj:reply-count>0</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://ermig.livejournal.com/169934.html</guid>
  <pubDate>Fri, 25 Nov 2011 13:27:38 GMT</pubDate>
  <title>Кошка на кактусе</title>
  <link>http://ermig.livejournal.com/169934.html</link>
  <description>Было дело, как-то кошка&lt;br /&gt;Не нашла себе лукошка.&lt;br /&gt;По пустыне долго шла,&lt;br /&gt;Кактус маленький нашла.&lt;br /&gt;Поместила на верхушку&lt;br /&gt;Свою маленькую тушку.&lt;br /&gt;Кактус вырос в высоту,&lt;br /&gt;Кошку видно за версту.&lt;br /&gt;И такое вот бывает,&lt;br /&gt;А народ теперь гадает...&lt;br /&gt;&lt;br /&gt;&lt;img alt=&quot;&quot; height=&quot;700&quot; src=&quot;http://demotivators.ru/media/posters/8773_dva-voprosa.jpg&quot; style=&quot;border-width: 0pt; border-style: solid;&quot; width=&quot;547&quot; /&gt;</description>
  <comments>http://ermig.livejournal.com/169934.html</comments>
  <lj:security>public</lj:security>
  <lj:reply-count>3</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://ermig.livejournal.com/169703.html</guid>
  <pubDate>Wed, 16 Nov 2011 07:59:14 GMT</pubDate>
  <title>Не пишется в ЖеЖе...</title>
  <link>http://ermig.livejournal.com/169703.html</link>
  <description>Хоть время интересное&lt;br /&gt;Настало, но уже&lt;br /&gt;Иссякло вдохновение -&lt;br /&gt;Не пишется в ЖеЖе...</description>
  <comments>http://ermig.livejournal.com/169703.html</comments>
  <lj:security>public</lj:security>
  <lj:reply-count>14</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://ermig.livejournal.com/169426.html</guid>
  <pubDate>Mon, 15 Aug 2011 08:48:03 GMT</pubDate>
  <title>Тонущий курс</title>
  <link>http://ermig.livejournal.com/169426.html</link>
  <description>Курс валюты плавает&lt;br /&gt;У зарубежных стран&lt;br /&gt;То вниз, то вверх он скачет -&lt;br /&gt;Таков у них изъян...&lt;br /&gt;&lt;br /&gt;Мы видя это дело,&lt;br /&gt;Своей дорогой шли:&lt;br /&gt;И к тонущему курсу&lt;br /&gt;В конце концов пришли!</description>
  <comments>http://ermig.livejournal.com/169426.html</comments>
  <category>экономика</category>
  <category>цены</category>
  <category>курс рубля</category>
  <category>кризис</category>
  <lj:security>public</lj:security>
  <lj:reply-count>6</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://ermig.livejournal.com/169180.html</guid>
  <pubDate>Mon, 18 Apr 2011 07:39:39 GMT</pubDate>
  <title>Требуется помощь в переводе программы на белорусский и украинский языки</title>
  <link>http://ermig.livejournal.com/169180.html</link>
  <description>Здравствуйте, уважаемые носители белорусского и украинского языка!&lt;br /&gt;&lt;br /&gt;Я уже достаточно долгое время разрабатываю бесплатную  программу по поиску на компьютере похожих изображений:&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;http://antidupl.narod.ru/russian/index.html&quot; rel=&quot;nofollow&quot;&gt;antidupl.narod.ru/russian/index.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Программа на настоящий момент поддерживает русский и  английский языки. В последней версии мне пользователи из других стран  прислали также перевод на испанский и итальянский язык. Мне бы хотелось  так же, что бы программа поддерживала белорусский и украинский языки, но к сожалению  я не настолько хорошо их знаю, а у автоматических переводчиков пока  качество ниже плинтуса. &lt;br /&gt;&lt;br /&gt;В связи с чем, мне  требуется помощь аудитории по переводу файла со  строковыми ресурсами.&lt;br /&gt;&lt;br /&gt;Желающие помочь, могут  обращаться на мыло &lt;a href=&quot;mailto:antidupl@rambler.ru&quot;&gt;antidupl@rambler.ru&lt;/a&gt;&amp;nbsp;  и я вам предоставлю все необходимые для этого данные.&lt;br /&gt;&lt;br /&gt;Заранее благодарен.&lt;br /&gt;</description>
  <comments>http://ermig.livejournal.com/169180.html</comments>
  <lj:security>public</lj:security>
  <lj:reply-count>3</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://ermig.livejournal.com/168880.html</guid>
  <pubDate>Wed, 13 Apr 2011 15:25:24 GMT</pubDate>
  <title>Группа маньяков</title>
  <link>http://ermig.livejournal.com/168880.html</link>
  <description>Нашей бравою спецслужбой,&lt;br /&gt;Не прошло и пару дней,&lt;br /&gt;Был опознан и задержан&lt;br /&gt;Террорист-маньяк-злодей!&lt;br /&gt;&lt;br /&gt;Он уже во всем признался:&lt;br /&gt;Вот уже который год&lt;br /&gt;Он один везде коварно&lt;br /&gt;Подрывает наш народ!&lt;br /&gt;&lt;br /&gt;Тут спецслужбам подфартило:&lt;br /&gt;Напрягли свой тонкий слух,&lt;br /&gt;И помощника поймали,&lt;br /&gt;А потом и целых двух...&lt;br /&gt;&lt;br /&gt;И уже во всем признались&lt;br /&gt;Три бомбиста-маньяка,&lt;br /&gt;Как все бомбы вместе клали,&lt;br /&gt;Чтоб взорвать наверняка.&lt;br /&gt;&lt;br /&gt;Психиатры всего мира&lt;br /&gt;Теперь будут точно знать:&lt;br /&gt;Что маньяки-одиночки&lt;br /&gt;Могут группой нападать!</description>
  <comments>http://ermig.livejournal.com/168880.html</comments>
  <lj:security>public</lj:security>
  <lj:reply-count>5</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://ermig.livejournal.com/168502.html</guid>
  <pubDate>Mon, 11 Apr 2011 06:39:30 GMT</pubDate>
  <title>Где сахар?</title>
  <link>http://ermig.livejournal.com/168502.html</link>
  <description>Где сахар и где масло?&lt;br /&gt;Я все узнать хотел,&lt;br /&gt;Но только Папа Коли&lt;br /&gt;Давно уже все съел...</description>
  <comments>http://ermig.livejournal.com/168502.html</comments>
  <lj:security>public</lj:security>
  <lj:reply-count>5</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://ermig.livejournal.com/168358.html</guid>
  <pubDate>Fri, 04 Mar 2011 13:10:20 GMT</pubDate>
  <title>Перед зеркалом</title>
  <link>http://ermig.livejournal.com/168358.html</link>
  <description>Руки-веточки, животик,&lt;br /&gt;Сколиоз и толстый зад - &lt;br /&gt;Разве в зеркале все это&lt;br /&gt;Ты увидеть будешь рад?&lt;br /&gt;&lt;br /&gt;От чего же телевизор&lt;br /&gt;И диван твои друзья?&lt;br /&gt;От чего без сигареты&lt;br /&gt;Обойтись ни как нельзя?&lt;br /&gt;&lt;br /&gt;Почему забыл бассейн&lt;br /&gt;И поход в спортивный зал?&lt;br /&gt;От чего с утра зарядку&lt;br /&gt;выполнять ты перестал?&lt;br /&gt;&lt;br /&gt;Так сожми в кулак всю волю,&lt;br /&gt;Воплоти свои мечты:&lt;br /&gt;Быть здоровым или хилым -&lt;br /&gt;Выбираешь только ты!</description>
  <comments>http://ermig.livejournal.com/168358.html</comments>
  <lj:security>public</lj:security>
  <lj:reply-count>3</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://ermig.livejournal.com/168098.html</guid>
  <pubDate>Mon, 14 Feb 2011 14:47:08 GMT</pubDate>
  <title>Валентинка</title>
  <link>http://ermig.livejournal.com/168098.html</link>
  <description>Хоть порою в этой жизни нам бывает не легко,&lt;br /&gt;Но я верю: у нас будет все с тобою хорошо!&lt;br /&gt;Не печалься, мое солнце, понапрасну не грусти,&lt;br /&gt;Море радости и счастья у нас будет впереди!</description>
  <comments>http://ermig.livejournal.com/168098.html</comments>
  <lj:security>public</lj:security>
  <lj:reply-count>1</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://ermig.livejournal.com/167692.html</guid>
  <pubDate>Mon, 24 Jan 2011 15:42:13 GMT</pubDate>
  <title>Первый день рождения </title>
  <link>http://ermig.livejournal.com/167692.html</link>
  <description>Вот он только что родился,&lt;br /&gt;Улыбнулся вот для нас,&lt;br /&gt;Первый раз перевернулся,&lt;br /&gt;Взял игрушку в первый раз.&lt;br /&gt;&lt;br /&gt;Первый раз вот встал в кроватке,&lt;br /&gt;Появился первый зуб,&lt;br /&gt;Первый раз невнятно: &amp;quot;Мама!&amp;quot; -&lt;br /&gt;Прозвучало с его губ.&lt;br /&gt;&lt;br /&gt;Возраст шел по дням, неделям&lt;br /&gt;И по месяцам... и вот,&lt;br /&gt;Наступил момент сынишке&lt;br /&gt;Набежал уж целый год.&lt;br /&gt;&lt;br /&gt;В день рождения первый самый&lt;br /&gt;Мы желаем, чтобы он&lt;br /&gt;Рос здоровым и веселым,&lt;br /&gt;Был заботой окружен,&lt;br /&gt;&lt;br /&gt;Чтоб уверенной походкой&lt;br /&gt;Шел на жизненном пути,&lt;br /&gt;Чтобы много дней рождений&lt;br /&gt;Еще было впереди!</description>
  <comments>http://ermig.livejournal.com/167692.html</comments>
  <lj:security>public</lj:security>
  <lj:reply-count>7</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://ermig.livejournal.com/167462.html</guid>
  <pubDate>Mon, 10 Jan 2011 14:30:56 GMT</pubDate>
  <title>Снеговик</title>
  <link>http://ermig.livejournal.com/167462.html</link>
  <description>Снег пушистый, мягкий, белый&lt;br /&gt;Устилает зимний лес,&lt;br /&gt;Что внутри себя скрывает&lt;br /&gt;Столько сказочных чудес.&lt;br /&gt;&lt;br /&gt;Я гуляю с своим сыном,&lt;br /&gt;Он в колясочке заснул.&lt;br /&gt;Потому с аллеи шумной&lt;br /&gt;На тропинку я свернул.&lt;br /&gt;&lt;br /&gt;Спит сынишка, ну а папа&lt;br /&gt;Бить баклуши не привык,&lt;br /&gt;Он слепил за это время&lt;br /&gt;На поляне снеговик...&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;http://pics.livejournal.com/ermig/pic/000071w5/&quot;&gt;&lt;img height=&quot;400&quot; border=&quot;0&quot; width=&quot;300&quot; src=&quot;http://pics.livejournal.com/ermig/pic/000071w5&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;</description>
  <comments>http://ermig.livejournal.com/167462.html</comments>
  <lj:security>public</lj:security>
  <lj:reply-count>3</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://ermig.livejournal.com/167400.html</guid>
  <pubDate>Mon, 03 Jan 2011 08:18:04 GMT</pubDate>
  <title>32</title>
  <link>http://ermig.livejournal.com/167400.html</link>
  <description>Лишь рассвет слегка занялся&lt;br /&gt;За окном моим едва,&lt;br /&gt;С ощущением проснулся:&lt;br /&gt;Мне сегодня тридцать два!&lt;br /&gt;&lt;br /&gt;Это много или мало?&lt;br /&gt;Промежуточный итог:&lt;br /&gt;И не юный, и не старый...&lt;br /&gt;Пришла зрелость на порог!</description>
  <comments>http://ermig.livejournal.com/167400.html</comments>
  <lj:security>public</lj:security>
  <lj:reply-count>28</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://ermig.livejournal.com/167116.html</guid>
  <pubDate>Tue, 07 Dec 2010 07:22:28 GMT</pubDate>
  <title>Послание депутатов Всебелорусского народного собрания Президенту</title>
  <link>http://ermig.livejournal.com/167116.html</link>
  <description>Мы внимаем твои речи&lt;br /&gt;С бурною овацией,&lt;br /&gt;Несогласие считаем&lt;br /&gt;С тобою провокацией!&lt;br /&gt;&lt;br /&gt;Попу мы тебе лизать&lt;br /&gt;Хоть всю жизнь готовые,&lt;br /&gt;Только ты нам подари&lt;br /&gt;Печи микроволновые!</description>
  <comments>http://ermig.livejournal.com/167116.html</comments>
  <lj:security>public</lj:security>
  <lj:reply-count>3</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://ermig.livejournal.com/166699.html</guid>
  <pubDate>Mon, 06 Dec 2010 13:28:29 GMT</pubDate>
  <title>Лукашенко: Космические технологии в Беларуси войдут в повседневный обиход</title>
  <link>http://ermig.livejournal.com/166699.html</link>
  <description>На работу на ракете&lt;br /&gt;Будем каждый день летать!&lt;br /&gt;И картошку на комете&lt;br /&gt;Мы научимся сажать!&lt;br /&gt;&lt;br /&gt;А с Титана подешевке&lt;br /&gt;Повезем сюда мы газ,&lt;br /&gt;Марсианские кредиты&lt;br /&gt;Будут льготные для нас!&lt;br /&gt;&lt;br /&gt;В общем будет без обмана&lt;br /&gt;Ждать осталось так- фигня,&lt;br /&gt;Это будет очень скоро...&lt;br /&gt;Голосуйте за меня!</description>
  <comments>http://ermig.livejournal.com/166699.html</comments>
  <category>космос</category>
  <category>Лукашенко</category>
  <category>выборы</category>
  <lj:security>public</lj:security>
  <lj:reply-count>4</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://ermig.livejournal.com/166563.html</guid>
  <pubDate>Thu, 18 Nov 2010 15:02:59 GMT</pubDate>
  <title>Первый шаг</title>
  <link>http://ermig.livejournal.com/166563.html</link>
  <description>Всем скажу я по секрету,&lt;br /&gt;Что вчера случилось так:&lt;br /&gt;Дести месяцев пусть нету,&lt;br /&gt;Сын мой сделал первый шаг!</description>
  <comments>http://ermig.livejournal.com/166563.html</comments>
  <category>дети</category>
  <category>Максим</category>
  <category>праздник</category>
  <lj:security>public</lj:security>
  <lj:reply-count>7</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://ermig.livejournal.com/166257.html</guid>
  <pubDate>Tue, 16 Nov 2010 09:17:40 GMT</pubDate>
  <title>Осенняя печаль</title>
  <link>http://ermig.livejournal.com/166257.html</link>
  <description>Несбывшиеся грезы&lt;br /&gt;Нам все немного жаль.&lt;br /&gt;Роняет тихо слезы &lt;br /&gt;Осенняя печаль.&lt;br /&gt;&lt;br /&gt;Дорогу закрывает&lt;br /&gt;Нам горизонтом дней.&lt;br /&gt;И ветер обрывает&lt;br /&gt;Последний лист с ветвей.&lt;br /&gt;&lt;br /&gt;Но прочь печаль, сомнения&lt;br /&gt;Коль жив ты и здоров.&lt;br /&gt;И видно небо синее&lt;br /&gt;В просвете облаков.</description>
  <comments>http://ermig.livejournal.com/166257.html</comments>
  <category>лирика</category>
  <category>погода</category>
  <lj:security>public</lj:security>
  <lj:reply-count>4</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://ermig.livejournal.com/166014.html</guid>
  <pubDate>Fri, 08 Oct 2010 08:08:04 GMT</pubDate>
  <title>Лукашенко: Экономические катаклизмы Беларуси не грозят</title>
  <link>http://ermig.livejournal.com/166014.html</link>
  <description>Говорят, народа слуги&lt;br /&gt;Могут только нагло врать.&lt;br /&gt;Но они нам намекают,&lt;br /&gt;Нужно только их понять.&lt;br /&gt;&lt;br /&gt;Если вдруг нам заявляют:&lt;br /&gt;Дефициту не бывать -&lt;br /&gt;В магазин бегите сразу&lt;br /&gt;Соль и спички покупать.&lt;br /&gt;&lt;br /&gt;Говорят, что безработных&lt;br /&gt;Будет меньше с каждым днем -&lt;br /&gt;Это значит скоро в отпуск&lt;br /&gt;Неоплаченный пойдем.&lt;br /&gt;&lt;br /&gt;Из Нацбанка если скажут:&lt;br /&gt;Золотой запас растет -&lt;br /&gt;То понятно рубль завтра&lt;br /&gt;Непременно упадет!&lt;br /&gt;&lt;br /&gt;Ну а если Батька вышел&lt;br /&gt;Успокаивать народ -&lt;br /&gt;Это значит сто пудово &lt;br /&gt;Жопа полная придет!</description>
  <comments>http://ermig.livejournal.com/166014.html</comments>
  <category>экономика</category>
  <category>Лукашенко</category>
  <category>кризис</category>
  <category>Ложь</category>
  <category>президент</category>
  <lj:security>public</lj:security>
  <lj:reply-count>9</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://ermig.livejournal.com/165797.html</guid>
  <pubDate>Thu, 07 Oct 2010 12:07:00 GMT</pubDate>
  <title>Оптимизация программы по скорости на примере медианного фильтра</title>
  <link>http://ermig.livejournal.com/165797.html</link>
  <description>&lt;h2&gt;Введение&lt;/h2&gt;   &lt;p align=&quot;justify&quot;&gt;В данной статье я решил привести пример оптимизации по скорости  исполнения алгоритма, предназначенного для обработки видео изображения.  В качестве примера, мной был выбран алгоритм медианной фильтрации.  Медианная фильтрация является эффективным способом подавления шумов,  которые неизбежно появляются на цифровых камерах в условиях малого  освещения сцены.  Алгоритм этот достаточно ресурсоемок &amp;ndash; так например, при обработке  серого изображения медианным фильтром 3х3 требуется порядка 50 операций  на одну точку изображения.  И если для обработки одиночных фотографий скорость в принципе не сильно  важна, то при обработке видео потока скорость обработки кадра является  критическим параметром при выборе алгоритма.&lt;/p&gt;  &lt;p align=&quot;justify&quot;&gt;Для справки напоминаю суть алгоритма:&lt;/p&gt;   &lt;ol&gt;&lt;li&gt;&lt;p align=&quot;justify&quot;&gt;Для каждой точки исходного изображения берется некоторая окрестность (в нашем случае 3x3).&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p align=&quot;justify&quot;&gt;Точки данной окрестности сортируются по возрастанию яркости.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p align=&quot;justify&quot;&gt;Средняя точка (5-я для фильтра 3х3) отсортированной окрестности записывается в итоговое изображение.&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;  &lt;p align=&quot;justify&quot;&gt;Для упрощения задачи я рассмотрел случай серого изображения (8 бит на  точку) без учета граничных эффектов - для этого для фильтрации бралась  центральная часть несколько большего изображения.  Конечно, в реальных задачах граничные точки изображения следует  рассчитывать по особому алгоритму, и порой реализация этих особых  алгоритмов может занимать большую часть кода.  Однако в плане общего времени исполнения алгоритма, эти особые точки  занимают, как правило, порядка нескольких процентов, потому не интересны  в контексте данного примера.  Кроме того для простоты я использовал однопоточный вариант алгоритма, но  эта задача в принципе может быть легко распараллелена на произвольное  число потоков.&lt;/p&gt;  &lt;a name=&quot;cutid1&quot;&gt;&lt;/a&gt;  &lt;h2&gt;0-й вариант реализации&lt;/h2&gt;    &lt;p align=&quot;justify&quot;&gt;В этой начальной реализации задача была решена в лоб: окрестность для  каждой точки исходного изображения копировалась во вспомогательный  массив, который затем сортировался при помощи функции &lt;code&gt;std::sort()&lt;/code&gt;.&lt;/p&gt;  &lt;pre&gt;
    void median_filter(unsigned char* src, int width, int height, int stride, unsigned char* dst)
    {
        int a[9];
        for(int y = 0; y &amp;lt; height; ++y)
        {
            for(int x = 0; x &amp;lt; width; ++x)
            {
                load(src + x, stride, a); //см. приложение
        	    std::sort(a, a + 9);
                dst[x] = (unsigned char)a[4];
            }
            dst += stride; 
            src += stride;
        }
    }
&lt;/pre&gt;  &lt;h2&gt;1-я оптимизация&lt;/h2&gt;    &lt;p align=&quot;justify&quot;&gt;У предыдущего метода, впрочем, сразу видно узкое место &amp;ndash; это стандартная  функции сортировки.   Она предназначена для сортировки массива произвольного размера, в ней  осуществляется множество внутренних проверок, потому она, скорее всего,  не будет оптимальным решением для данной задачи, где массив мал и имеет  фиксированный размер.  Кроме того, нам совсем не обязательно полностью сортировать массив,  достаточно, что бы в 4-м элементе было требуемое нами значение.  Потому мы можем применить метод сортировки &amp;laquo;сетью&amp;raquo;.  Кроме того вызов сам функций в теле цикла также вызывает дополнительные  накладные расходы, потому функцию сортировки мы сделаем inline:&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;  &lt;pre&gt;
    inline void sort(int&amp;amp; a, int&amp;amp; b) // сортирует пару чисел
    {
        if(a &amp;gt; b)
        {
            int t = a;
            a = b;
            b = t;
        }
    }

    inline void sort(int a[9]) //частично сортирует весь массив
    {
        sort(a[1], a[2]); sort(a[4], a[5]); sort(a[7], a[8]); 
        sort(a[0], a[1]); sort(a[3], a[4]); sort(a[6], a[7]);
        sort(a[1], a[2]); sort(a[4], a[5]); sort(a[7], a[8]); 
        sort(a[0], a[3]); sort(a[5], a[8]); sort(a[4], a[7]);
        sort(a[3], a[6]); sort(a[1], a[4]); sort(a[2], a[5]); 
        sort(a[4], a[7]); sort(a[4], a[2]); sort(a[6], a[4]);
        sort(a[4], a[2]);
    }
&lt;/pre&gt;  &lt;h2&gt;2-я оптимизация&lt;/h2&gt;    &lt;p align=&quot;justify&quot;&gt;Хотя  первый метод и получился значительно быстрее нулевого (см.  результат тестирования ниже), но у него осталось одно узкое место &amp;ndash; в  этом методе очень много условных переходов.  Как известно, современные процессоры очень их не любят, так как имеют  конвейерную архитектуру и возможность внеочередного исполнения  нескольких команд за один такт.  И для первого, и для второго условные переходы крайне нежелательны, так  как процессор должен останавливаться и ждать результатов вычислений,  чтобы узнать по какой ветке программы ему следует идти дальше.  К счастью сортировку двух 8 битных значений вполне можно реализовать и  без условных переходов:&lt;/p&gt;  &lt;pre&gt;
    inline void sort(int&amp;amp; a, int&amp;amp; b)
    {
        int d = a - b;
        int m = ~(d &amp;gt;&amp;gt; 8);
        b += d&amp;amp;m;
        a -= d&amp;amp;m;
    }
&lt;/pre&gt;  &lt;h2&gt;3-я оптимизация&lt;/h2&gt;    &lt;p align=&quot;justify&quot;&gt;В принципе предыдущей оптимизации уже вполне достаточно, однако можно еще немного оптимизировать функцию &lt;code&gt;void sort(int&amp;amp; a, int&amp;amp; b)&lt;/code&gt; с применением вспомогательног массива.  Однако останавливаться здесь подробно на нем я не буду, так эта оптимизация не дает существенного ускорения работы алгоритма.  Впрочем все желающие могут посмотреть его реализацию в приложении.&lt;/p&gt;  &lt;h2&gt;4-я оптимизация&lt;/h2&gt;   &lt;p align=&quot;justify&quot;&gt;До сих пор мы оставались в рамках стандратного С++ и не учитывали все  возможности современных процессоров.  Однако еще начина с процессора Pentium-MMX в процессорах появилась  поддержка MMX (Multimedia Extensions) инструкций для векторной обработки  данных.  В частности, команды MMX могут исполнять целочисленные векторные  операции сразу над 8-ю 8-битными числами за раз.  А начиная с процессоров Pentium-IV и Athlon-64 появилась поддержка  инструкций из набора SSE2 (Streaming SIMD Extensions), которые   позволяют обрабатывать целочисленные векторные операции сразу над 16-ю  8-битными числами за раз.  Сразу понятно, что теоретически использование SSE2 инструкций может  потенциально ускорить программу 16 раз, потому глупо не попытаться их  использовать.&lt;/p&gt;  &lt;p align=&quot;justify&quot;&gt;К счастью, для того, чтобы задействовать инструкции из набора SSE2,  совсем не обязательно использовать ассемблер.  Большинство современных С++ компиляторов имеют поддержку intrinsics  (встроенных функций, с помощью которых можно задействовать всевозможные  расширения процессоров).  Программирование с использованием  intrinsics практически не отличается  от программирования на чистом С.  Intrinsic функции преобразуются компилятором напрямую в инструкции  процессора, хотя при этом работа непосредственно с регистрами процессора  остается скрытой от программиста.  В большистве случаев программа с использованием intrinsics не уступает в  быстродействии программе, написанной на ассемблере.&lt;/p&gt;  &lt;p align=&quot;justify&quot;&gt;Целочисленные комманды SSE2  определены в заголовочном файле &lt;code&gt; &amp;lt; emmintrin.h &amp;gt; &lt;/code&gt;.  В качестве базового типа выступает &lt;code&gt;__m128i&lt;/code&gt; - 128 битный  вектор, который в зависимости от контекста может интерпетироваться как  набор 2-х 64 битных, 4-х 32 битных, 8-х 16 битных, 16-х 8 битных  знаковых или беззнаковых чисел.   Как видно, поддерживают не только векторные арифметические операции, но  также векторные логические операции, а также векторные операции загрузки  и выгрузки данных.  Ниже приведен 4-й вариант оптимизации медианного фильтра при помощи SSE2  инструкций.  Код, как мне кажется, довольно нагляден.&lt;/p&gt;  &lt;pre&gt;
    inline void sort(__m128i&amp;amp; a, __m128i&amp;amp; b)
    {
        const __m128i t = a;
        a = _mm_min_epu8(t, b); //нахождение минимума 2-х 8 битных безннаковых чисел для каждого из 16 значений вектора
        b = _mm_max_epu8(t, b); //нахождение максимума 2-х 8 битных безннаковых чисел для каждого из 16 значений вектора
    }

    inline void sort(__m128i a[9])
    {
        sort(a[1], a[2]); sort(a[4], a[5]); sort(a[7], a[8]); 
        sort(a[0], a[1]); sort(a[3], a[4]); sort(a[6], a[7]);
        sort(a[1], a[2]); sort(a[4], a[5]); sort(a[7], a[8]); 
        sort(a[0], a[3]); sort(a[5], a[8]); sort(a[4], a[7]);
        sort(a[3], a[6]); sort(a[1], a[4]); sort(a[2], a[5]); 
        sort(a[4], a[7]); sort(a[4], a[2]); sort(a[6], a[4]);
        sort(a[4], a[2]);
    }

    inline void load(unsigned char* src, int stride, __m128i a[9])
    {
        a[0] = _mm_loadu_si128((__m128i*)(src - 1 - stride)); //загрузка 128 битного вектора по невыровненному по 16 битной границе адресу
        a[1] = _mm_load_si128((__m128i*)(src - stride)); //загрузка 128 битного вектора по выровненному по 16 битной границе адресу
        a[2] = _mm_loadu_si128((__m128i*)(src + 1 - stride));

        a[3] = _mm_loadu_si128((__m128i*)(src - 1));
        a[4] = _mm_load_si128((__m128i*)(src));
        a[5] = _mm_loadu_si128((__m128i*)(src + 1));

        a[6] = _mm_loadu_si128((__m128i*)(src - 1 + stride));
        a[7] = _mm_load_si128((__m128i*)(src + stride));
        a[8] = _mm_loadu_si128((__m128i*)(src + 1 + stride));
    }

    void median_filter(unsigned char* src, int width, int height, int stride, unsigned char* dst)
    {
        __m128i a[9];
        for(int y = 0; y &amp;lt; height; y++)
        {
            for(int x = 0; x &amp;lt; width; x += sizeof(__m128i))
            {
                load(src + x, stride, a);
                sort(a);
                _mm_store_si128((__m128i*)(dst + x), a[4]); //сохранение 128 битного вектора по выровненному по 16 битной границе адресу
            }
            dst += stride; 
            src += stride;
        }
    }
&lt;/pre&gt;   &lt;h2&gt;Тестирование&lt;/h2&gt;   &lt;p align=&quot;justify&quot;&gt;Тестирование производилось на серых изображениях размером 1 MB.  Для повышения точности измерения времени, тесты прогонялись несколько  раз.  Время выполнения получали делением общего времени исполнения тестов на  количество прогонов.  Количество прогонов выбиралось таким образом, что общее время исполнения  было не меньше 1 секунды, что должно обеспечить два знака точности при  измерении времени исполнения алгоритмов.  Всего было протестировано 5 вариантов решения задачи:&lt;/p&gt;   &lt;ol&gt;&lt;li&gt;&lt;p align=&quot;justify&quot;&gt;0-й вариант с использованием стандартной сортировки.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p align=&quot;justify&quot;&gt;1-й вариант с использованием сортировки &amp;quot;сетью&amp;quot;.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p align=&quot;justify&quot;&gt;2-й вариант с использованием сортировки &amp;quot;сетью&amp;quot; + без использования условных переходов.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p align=&quot;justify&quot;&gt;3-й вариант с использованием сортировки &amp;quot;сетью&amp;quot; + без использования  условных переходов (метод с применением вспомогательного массива) .&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p align=&quot;justify&quot;&gt;4-й вариант с оптимизацией под SSE2 расширение процессора.&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;  &lt;p align=&quot;justify&quot;&gt;Исходные коды теста находятся в приложении (см. ниже).  Тест был скомпилирован с максимальной оптимизацией под Microsoft Visual  Studio 2008 и был запущен на нескольких машинах со следующими  результатами:&lt;/p&gt;  &lt;table width=&quot;720&quot; border=&quot;1&quot; style=&quot;border-collapse: collapse;&quot;&gt;  &lt;tbody&gt;&lt;tr&gt;   &lt;td&gt;&lt;b&gt;Производитель&lt;/b&gt;&lt;/td&gt;    &lt;td align=&quot;center&quot; colspan=&quot;3&quot;&gt;Intel&lt;/td&gt;    &lt;td align=&quot;center&quot; colspan=&quot;3&quot;&gt;AMD&lt;/td&gt;  &lt;/tr&gt;  &lt;tr&gt;   &lt;td&gt;&lt;b&gt;Название&lt;/b&gt;&lt;/td&gt;    &lt;td align=&quot;center&quot;&gt;Core i5 750&lt;/td&gt;    &lt;td align=&quot;center&quot;&gt;Core 2 Due&lt;/td&gt;    &lt;td align=&quot;center&quot;&gt;T2080&lt;/td&gt;    &lt;td align=&quot;center&quot;&gt;Phenom II X6&lt;/td&gt;   &lt;td align=&quot;center&quot;&gt;Athlon 64 X2&lt;/td&gt;   &lt;td align=&quot;center&quot;&gt;Athlon&lt;/td&gt;  &lt;/tr&gt;  &lt;tr&gt;   &lt;td&gt;&lt;b&gt;Частота, GHz&lt;/b&gt;&lt;/td&gt;    &lt;td align=&quot;center&quot;&gt;2.67&lt;/td&gt;    &lt;td align=&quot;center&quot;&gt;2.3&lt;/td&gt;    &lt;td align=&quot;center&quot;&gt;1.7&lt;/td&gt;    &lt;td align=&quot;center&quot;&gt;2.8&lt;/td&gt;   &lt;td align=&quot;center&quot;&gt;2,8&lt;/td&gt;   &lt;td align=&quot;center&quot;&gt;0,8&lt;/td&gt;  &lt;/tr&gt;  &lt;tr&gt;   &lt;td&gt;&lt;b&gt;Название теста&lt;/b&gt;&lt;/td&gt;    &lt;td align=&quot;center&quot; colspan=&quot;6&quot;&gt;&lt;b&gt;Среднее время исполнения, мс&lt;/b&gt;&lt;/td&gt;   &lt;/tr&gt;  &lt;tr&gt;   &lt;td&gt;&lt;b&gt;base::median_filter with std::sort&lt;/b&gt;&lt;/td&gt;    &lt;td align=&quot;center&quot;&gt;141&lt;/td&gt;    &lt;td align=&quot;center&quot;&gt;165&lt;/td&gt;    &lt;td align=&quot;center&quot;&gt;239&lt;/td&gt;    &lt;td align=&quot;center&quot;&gt;102&lt;/td&gt;   &lt;td align=&quot;center&quot;&gt;126&lt;/td&gt;   &lt;td align=&quot;center&quot;&gt;516&lt;/td&gt;  &lt;/tr&gt;  &lt;tr&gt;   &lt;td&gt;&lt;b&gt;base::median_filter with sorter_v1&lt;/b&gt;&lt;/td&gt;    &lt;td align=&quot;center&quot;&gt;46.7&lt;/td&gt;    &lt;td align=&quot;center&quot;&gt;59.4&lt;/td&gt;    &lt;td align=&quot;center&quot;&gt;76.6&lt;/td&gt;    &lt;td align=&quot;center&quot;&gt;39.9&lt;/td&gt;   &lt;td align=&quot;center&quot;&gt;65.8&lt;/td&gt;   &lt;td align=&quot;center&quot;&gt;170&lt;/td&gt;  &lt;/tr&gt;  &lt;tr&gt;   &lt;td&gt;&lt;b&gt;base::median_filter with sorter_v2&lt;/b&gt;&lt;/td&gt;    &lt;td align=&quot;center&quot;&gt;26.7&lt;/td&gt;    &lt;td align=&quot;center&quot;&gt;37.1&lt;/td&gt;    &lt;td align=&quot;center&quot;&gt;58.4&lt;/td&gt;    &lt;td align=&quot;center&quot;&gt;25.3&lt;/td&gt;   &lt;td align=&quot;center&quot;&gt;40.8&lt;/td&gt;   &lt;td align=&quot;center&quot;&gt;142&lt;/td&gt;  &lt;/tr&gt;  &lt;tr&gt;   &lt;td&gt;&lt;b&gt;base::median_filter with sorter_v3&lt;/b&gt;&lt;/td&gt;    &lt;td align=&quot;center&quot;&gt;24.1&lt;/td&gt;    &lt;td align=&quot;center&quot;&gt;29.7&lt;/td&gt;    &lt;td align=&quot;center&quot;&gt;41.2&lt;/td&gt;    &lt;td align=&quot;center&quot;&gt;23.7&lt;/td&gt;   &lt;td align=&quot;center&quot;&gt;47.6&lt;/td&gt;   &lt;td align=&quot;center&quot;&gt;131&lt;/td&gt;  &lt;/tr&gt;  &lt;tr&gt;   &lt;td&gt;&lt;b&gt;sse2::median_filter&lt;/b&gt;&lt;/td&gt;    &lt;td align=&quot;center&quot;&gt;0.636&lt;/td&gt;    &lt;td align=&quot;center&quot;&gt;1.48&lt;/td&gt;    &lt;td align=&quot;center&quot;&gt;3.69&lt;/td&gt;    &lt;td align=&quot;center&quot;&gt;0.808&lt;/td&gt;   &lt;td align=&quot;center&quot;&gt;1.80&lt;/td&gt;   &lt;td align=&quot;center&quot;&gt;---&lt;/td&gt;  &lt;/tr&gt;  &lt;tr&gt;   &lt;td&gt;&lt;b&gt;Название теста&lt;/b&gt;&lt;/td&gt;    &lt;td align=&quot;center&quot; colspan=&quot;6&quot;&gt;&lt;b&gt;Относительный/абсолютный выигрыш от оптимизации&lt;/b&gt;&lt;/td&gt;   &lt;/tr&gt;  &lt;tr&gt;   &lt;td&gt;&lt;b&gt;base::median_filter with sorter_v1&lt;/b&gt;&lt;/td&gt;    &lt;td align=&quot;center&quot;&gt;3.0 / 3.0&lt;/td&gt;    &lt;td align=&quot;center&quot;&gt;2.8 / 2.8&lt;/td&gt;    &lt;td align=&quot;center&quot;&gt;3.1 / 3.1&lt;/td&gt;    &lt;td align=&quot;center&quot;&gt;2.6 / 2.6&lt;/td&gt;   &lt;td align=&quot;center&quot;&gt;1.9 / 1.9&lt;/td&gt;   &lt;td align=&quot;center&quot;&gt;3.0 / 3.0&lt;/td&gt;  &lt;/tr&gt;  &lt;tr&gt;   &lt;td&gt;&lt;b&gt;base::median_filter with sorter_v2&lt;/b&gt;&lt;/td&gt;    &lt;td align=&quot;center&quot;&gt;1.7 / 5.3&lt;/td&gt;    &lt;td align=&quot;center&quot;&gt;1.6 / 4.4&lt;/td&gt;    &lt;td align=&quot;center&quot;&gt;1.3 / 4.1&lt;/td&gt;    &lt;td align=&quot;center&quot;&gt;1.6 / 4.0&lt;/td&gt;   &lt;td align=&quot;center&quot;&gt;1.6 / 3.0&lt;/td&gt;   &lt;td align=&quot;center&quot;&gt;1.2 / 3.6&lt;/td&gt;  &lt;/tr&gt;  &lt;tr&gt;   &lt;td&gt;&lt;b&gt;base::median_filter with sorter_v3&lt;/b&gt;&lt;/td&gt;    &lt;td align=&quot;center&quot;&gt;1.1 / 5.9&lt;/td&gt;    &lt;td align=&quot;center&quot;&gt;1.2 / 5.6&lt;/td&gt;    &lt;td align=&quot;center&quot;&gt;1.4 / 5.8&lt;/td&gt;    &lt;td align=&quot;center&quot;&gt;1.1 / 4.3&lt;/td&gt;   &lt;td align=&quot;center&quot;&gt;0.9 / 2.6&lt;/td&gt;   &lt;td align=&quot;center&quot;&gt;1.1 / 3.9&lt;/td&gt;  &lt;/tr&gt;  &lt;tr&gt;   &lt;td&gt;&lt;b&gt;sse2::median_filter&lt;/b&gt;&lt;/td&gt;    &lt;td align=&quot;center&quot;&gt;37.9 / 222&lt;/td&gt;    &lt;td align=&quot;center&quot;&gt;20.1 / 111&lt;/td&gt;    &lt;td align=&quot;center&quot;&gt;11.2 / 64.8&lt;/td&gt;    &lt;td align=&quot;center&quot;&gt;29.3 / 126&lt;/td&gt;   &lt;td align=&quot;center&quot;&gt;22.6 / 70&lt;/td&gt;   &lt;td align=&quot;center&quot;&gt;-- / --&lt;/td&gt;  &lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;  &lt;p align=&quot;justify&quot;&gt;&lt;i&gt;Примечание: процессоры AMD Athlon не поддерживают инструкции из набора SSE2.&lt;/i&gt;&lt;/p&gt;  &lt;h2&gt;Выводы&lt;/h2&gt;   &lt;p align=&quot;justify&quot;&gt;На основании результатов тестов можно сделать следующие выводы:&lt;/p&gt;   &lt;ol&gt;&lt;li&gt;&lt;p align=&quot;justify&quot;&gt;При помощи стандартных средств C++ данный алгоритм может быть оптимизирован по скорости в 4-6 раз.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p align=&quot;justify&quot;&gt;С применением инструкций SSE2 данный алгоритм можно еще ускорить в 10-40 раз.  Это достаточно большая величина, которая перекрывает, как мне кажется, минусы отхода от потери переносимости стандартного C++.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p align=&quot;justify&quot;&gt;Если соотнести время исполнения SSE2 и  частоту процессоров, то можно  судить о количестве инструкций SSE2 выполняемых данным процессором за  один такт.  Особенно это хорошо видно на примере процессоров Intel.  Так настольный процессор  Core 2 Due  выполняет по одной операции SSE2  за такт, с мобильный процессор T2080 может выполнять лишь одну операцию  за два такта.  В тоже время новые процессоры  Core i5 значительно ускорились и явно  могут обрабатывать по 2 такие операции за такт.&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;  &lt;h2&gt;Приложение&lt;/h2&gt;   &lt;p align=&quot;justify&quot;&gt;Код тестовой программы (написан на C++ под Microsoft Visual Studio 2008):&lt;/p&gt;  &lt;pre&gt;
#include &amp;lt; iostream&amp;gt;
#include &amp;lt; algorithm&amp;gt;
#include &amp;lt; windows.h&amp;gt;
#include &amp;lt; emmintrin.h&amp;gt;

namespace base
{
    const int saturate[] = 
    {
        0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
        0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
        0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
        0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
        0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
        0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
        0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
        0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
        0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
        0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
        0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
        0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
        0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
        0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
        0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
        0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
        0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,  15,
        16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29,  30,  31,
        32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,
        48,  49,  50,  51,  52,  53,  54,  55,  56,  57,  58,  59,  60,  61,  62,  63,
        64,  65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75,  76,  77,  78,  79,
        80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90,  91,  92,  93,  94,  95,
        96,  97,  98,  99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
        112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
        128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
        144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
        160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
        176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,
        192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
        208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
        224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
        240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255,
        255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
        255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
        255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
        255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
        255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
        255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
        255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
        255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
        255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
        255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
        255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
        255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
        255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
        255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
        255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
        255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
        255
    };

    __forceinline int cast(int t) 
    {
        return saturate[t + 256];
    }

    struct sorter_v0
    {
    };

    struct sorter_v1
    {
        __forceinline void operator() (int&amp;amp; a, int&amp;amp; b)
        {
            if(a &amp;gt; b)
            {
                int t = a;
                a = b;
                b = t;
            }
        }
    };

    struct sorter_v2
    {
        __forceinline void operator() (int&amp;amp; a, int&amp;amp; b)
        {
            int d = a - b;
            int m = ~(d &amp;gt;&amp;gt; 8);
            b += d&amp;amp;m;
            a -= d&amp;amp;m;
        }
    };

    struct sorter_v3
    {
        __forceinline void operator() (int&amp;amp; a, int&amp;amp; b)
        {
            int t = cast(a - b);
            b += t;
            a -= t;
        }
    };

    template &amp;lt; class Sorter&amp;gt; __forceinline void sort(int a[9], Sorter sorter)
    {
        sorter(a[1], a[2]); sorter(a[4], a[5]); sorter(a[7], a[8]); 
        sorter(a[0], a[1]); sorter(a[3], a[4]); sorter(a[6], a[7]);
        sorter(a[1], a[2]); sorter(a[4], a[5]); sorter(a[7], a[8]); 
        sorter(a[0], a[3]); sorter(a[5], a[8]); sorter(a[4], a[7]);
        sorter(a[3], a[6]); sorter(a[1], a[4]); sorter(a[2], a[5]); 
        sorter(a[4], a[7]); sorter(a[4], a[2]); sorter(a[6], a[4]);
        sorter(a[4], a[2]);
    }

    template &amp;lt;&amp;gt; __forceinline void sort&amp;lt; sorter_v0&amp;gt;(int a[9], sorter_v0 sorter)
    {
        std::sort(a, a + 9);
    }

    __forceinline void load(unsigned char* src, int stride, int a[9])
    {
        a[0] = src[-1 - stride];  
        a[1] = src[-stride]; 
        a[2] = src[1 - stride];

        a[3] = src[-1];         
        a[4] = src[0];              
        a[5] = src[1];

        a[6] = src[-1 + stride];  
        a[7] = src[stride];  
        a[8] = src[1 + stride];
    }

    template &amp;lt; class Sorter&amp;gt; void median_filter(unsigned char* src, int width, int height, int stride, unsigned char* dst, Sorter sorter)
    {
        int a[9];
        for(int y = 0; y &amp;lt; height; y++)
        {
            for(int x = 0; x &amp;lt; width; ++x)
            {
                load(src + x, stride, a);
                sort(a, sorter);
                dst[x] = (unsigned char)a[4];
            }
            dst += stride; 
            src += stride;
        }
    }
}

namespace sse2
{
    __forceinline void sort(__m128i&amp;amp; a, __m128i&amp;amp; b)
    {
        const __m128i t = a;
        a = _mm_min_epu8(t, b);
        b = _mm_max_epu8(t, b);
    }

    __forceinline void sort(__m128i a[9])
    {
        sort(a[1], a[2]); sort(a[4], a[5]); sort(a[7], a[8]); 
        sort(a[0], a[1]); sort(a[3], a[4]); sort(a[6], a[7]);
        sort(a[1], a[2]); sort(a[4], a[5]); sort(a[7], a[8]); 
        sort(a[0], a[3]); sort(a[5], a[8]); sort(a[4], a[7]);
        sort(a[3], a[6]); sort(a[1], a[4]); sort(a[2], a[5]); 
        sort(a[4], a[7]); sort(a[4], a[2]); sort(a[6], a[4]);
        sort(a[4], a[2]);
    }

    __forceinline void load(unsigned char* src, int stride, __m128i a[9])
    {
        a[0] = _mm_loadu_si128((__m128i*)(src - 1 - stride));
        a[1] = _mm_load_si128((__m128i*)(src - stride));
        a[2] = _mm_loadu_si128((__m128i*)(src + 1 - stride));

        a[3] = _mm_loadu_si128((__m128i*)(src - 1));
        a[4] = _mm_load_si128((__m128i*)(src));
        a[5] = _mm_loadu_si128((__m128i*)(src + 1));

        a[6] = _mm_loadu_si128((__m128i*)(src - 1 + stride));
        a[7] = _mm_load_si128((__m128i*)(src + stride));
        a[8] = _mm_loadu_si128((__m128i*)(src + 1 + stride));
    }

    void median_filter(unsigned char* src, int width, int height, int stride, unsigned char* dst)
    {
        __m128i a[9];
        for(int y = 0; y &amp;lt; height; y++)
        {
            for(int x = 0; x &amp;lt; width; x += sizeof(__m128i))
            {
                load(src + x, stride, a);
                sort(a);
                _mm_store_si128((__m128i*)(dst + x), a[4]);
            }
            dst += stride; 
            src += stride;
        }
    }
}

struct Image
{
    int width;
    int height;
    int stride;
    unsigned char* data;

    Image(int width_, int height_)
    {
        width = width_;
        height = height_;
        stride = (width/sizeof(__m128i) + 2 + (width%sizeof(__m128i) ? 1 : 0))*sizeof(__m128i);
        m_data = (unsigned char*)_mm_malloc(stride*(height + 2), sizeof(__m128i));
        data = m_data + stride + sizeof(__m128i);
        memset(m_data, 0, stride*(height + 2));
    }

    ~Image()
    {
        _mm_free(m_data);
    }

    bool operator==(const Image &amp;image;)
    {
        return 
            width == image.width &amp;amp;&amp;amp; height == image.height &amp;amp;&amp;amp; 
            memcmp(m_data, image.m_data, stride*(height + 2)) == 0;
    }

    void Fill(int seed)
    {
        srand(seed);
        for(int row = 0; row &amp;lt; height; row++)
            for(int col = 0; col &amp;lt; width; col++)
                data[stride*row + col] = (rand()*255)/RAND_MAX;
    }

private:
    unsigned char* m_data;
};

double GetTime()
{
    LARGE_INTEGER freq, count;
    QueryPerformanceFrequency(&amp;amp;freq);
    QueryPerformanceCounter(&amp;amp;count);
    return 1.0 / (freq.HighPart * (double)0xffffffff + freq.LowPart) * 
        (count.HighPart * (double)0xffffffff + count.LowPart);
}

int main()
{
    const int w = 1024;
    const int h = 1024;

    Image src(w, h), dst0(w, h), dst1(w, h), dst2(w, h), dst3(w, h), dst4(w, h);

    src.Fill(1);

    {
        const int n = 10;
        double t = GetTime();
        for(int i = 0; i &amp;lt; n; i++)
            base::median_filter(src.data, src.width, src.height, src.stride, dst0.data, base::sorter_v0());
        t = GetTime() - t;
        std::cout &amp;lt;&amp;lt; &amp;quot;C++ base::median_filter with std::sort time = &amp;quot; &amp;lt;&amp;lt; t/n*1000 &amp;lt;&amp;lt; &amp;quot; ms&amp;quot; &amp;lt;&amp;lt; std::endl;
    }

    {
        const int n = 30;
        double t = GetTime();
        for(int i = 0; i &amp;lt; n; i++)
            base::median_filter(src.data, src.width, src.height, src.stride, dst1.data, base::sorter_v1());
        t = GetTime() - t;
        std::cout &amp;lt;&amp;lt; &amp;quot;C++ base::median_filter with sorter_v1 time = &amp;quot; &amp;lt;&amp;lt; t/n*1000 &amp;lt;&amp;lt; &amp;quot; ms&amp;quot; &amp;lt;&amp;lt; std::endl;
        if(!(dst0 == dst1))
            std::cout &amp;lt;&amp;lt; &amp;quot;C++ base::median_filter with sorter_v1 error!&amp;quot; &amp;lt;&amp;lt; std::endl;
    }

    {
        const int n = 50;
        double t = GetTime();
        for(int i = 0; i &amp;lt; n; i++)
            base::median_filter(src.data, src.width, src.height, src.stride, dst2.data, base::sorter_v2());
        t = GetTime() - t;
        std::cout &amp;lt;&amp;lt; &amp;quot;C++ base::median_filter with sorter_v2 time = &amp;quot; &amp;lt;&amp;lt; t/n*1000 &amp;lt;&amp;lt; &amp;quot; ms&amp;quot; &amp;lt;&amp;lt; std::endl;
        if(!(dst0 == dst2))
            std::cout &amp;lt;&amp;lt; &amp;quot;C++ base::median_filter with sorter_v2 error!&amp;quot; &amp;lt;&amp;lt; std::endl;
    }

    {
        const int n = 60;
        double t = GetTime();
        for(int i = 0; i &amp;lt; n; i++)
            base::median_filter(src.data, src.width, src.height, src.stride, dst3.data, base::sorter_v3());
        t = GetTime() - t;
        std::cout &amp;lt;&amp;lt; &amp;quot;C++ base::median_filter with sorter_v3 time = &amp;quot; &amp;lt;&amp;lt; t/n*1000 &amp;lt;&amp;lt; &amp;quot; ms&amp;quot; &amp;lt;&amp;lt; std::endl;
        if(!(dst0 == dst3))
            std::cout &amp;lt;&amp;lt; &amp;quot;C++ base::median_filter with sorter_v3 error!&amp;quot; &amp;lt;&amp;lt; std::endl;
    }

    {
        const int n = 2000;
        double t = GetTime();
        for(int i = 0; i &amp;lt; n; i++)
            sse2::median_filter(src.data, src.width, src.height, src.stride, dst4.data);
        t = GetTime() - t;
        std::cout &amp;lt;&amp;lt; &amp;quot;C++ sse2::median_filter time = &amp;quot; &amp;lt;&amp;lt; t/n*1000 &amp;lt;&amp;lt; &amp;quot; ms&amp;quot; &amp;lt;&amp;lt; std::endl;
        if(!(dst0 == dst4))
            std::cout &amp;lt;&amp;lt; &amp;quot;C++ sse2::median_filter error!&amp;quot; &amp;lt;&amp;lt; std::endl;
    }
}
&lt;/pre&gt;
&lt;a name=&apos;cutid1-end&apos;&gt;&lt;/a&gt;</description>
  <comments>http://ermig.livejournal.com/165797.html</comments>
  <category>sse2</category>
  <category>медианный фильтр</category>
  <category>программирование</category>
  <category>оптимизация</category>
  <category>c++</category>
  <lj:security>public</lj:security>
  <lj:reply-count>11</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://ermig.livejournal.com/165431.html</guid>
  <pubDate>Wed, 06 Oct 2010 10:57:08 GMT</pubDate>
  <title>На обед!</title>
  <link>http://ermig.livejournal.com/165431.html</link>
  <description>Аппетит во мне проснулся,&lt;br /&gt;Потому давай, сосед,&lt;br /&gt;Коли нету возражений,&lt;br /&gt;Выдвигаться на обед!</description>
  <comments>http://ermig.livejournal.com/165431.html</comments>
  <category>обед</category>
  <lj:security>public</lj:security>
  <lj:reply-count>0</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://ermig.livejournal.com/165230.html</guid>
  <pubDate>Fri, 01 Oct 2010 11:58:34 GMT</pubDate>
  <title>Юра, приезжай!</title>
  <link>http://ermig.livejournal.com/165230.html</link>
  <description>Если ты был самым главным,&lt;br /&gt;Но тебе не повезло -&lt;br /&gt;Был уволен или свергнут&lt;br /&gt;В своем царстве, как назло.&lt;br /&gt;&lt;br /&gt;В телевизоре ругают&lt;br /&gt;И грозят привлечь к суду,&lt;br /&gt;Заморозить миллионы,&lt;br /&gt;Что хранятся на счету...&lt;br /&gt;&lt;br /&gt;Но не надо огорчаться &lt;br /&gt;И напрасно слезы лить,&lt;br /&gt;Нужно только Беларусь вам&lt;br /&gt;Поскорее посетить!&lt;br /&gt;&lt;br /&gt;Всем диктаторам тут бывшим&lt;br /&gt;Лукашенко даст приют...&lt;br /&gt;Может быть настанет время -&lt;br /&gt;И ему приют дадут?&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;P.S. &lt;/strong&gt;сей опус - немного переделанный ранее вариант про Бакиева.</description>
  <comments>http://ermig.livejournal.com/165230.html</comments>
  <category>отстранение от власти</category>
  <category>Лукашенко</category>
  <category>диктатор</category>
  <category>Лужков</category>
  <lj:security>public</lj:security>
  <lj:reply-count>2</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://ermig.livejournal.com/164891.html</guid>
  <pubDate>Tue, 28 Sep 2010 14:45:37 GMT</pubDate>
  <title>Пиши обе!</title>
  <link>http://ermig.livejournal.com/164891.html</link>
  <description>Хоть убейте, президента&lt;br /&gt;Не могу никак понять:&lt;br /&gt;Ну зачем ему так часто&lt;br /&gt;День рождения менять?&lt;br /&gt;&lt;br /&gt;Коль ты не определился&lt;br /&gt;С днем рожденья своего:&lt;br /&gt;Иль тридцатого родился,&lt;br /&gt;Или тридцать первого.&lt;br /&gt;&lt;br /&gt;Коли обе эти даты&lt;br /&gt;У тебя в мозгу живут,&lt;br /&gt;Запиши их обе в паспорт:&lt;br /&gt;Не стесняйся, все поймут!</description>
  <comments>http://ermig.livejournal.com/164891.html</comments>
  <category>день рождения</category>
  <category>президент</category>
  <lj:security>public</lj:security>
  <lj:reply-count>3</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://ermig.livejournal.com/164783.html</guid>
  <pubDate>Tue, 28 Sep 2010 12:02:24 GMT</pubDate>
  <title>Колобок не ушел от медведя...</title>
  <link>http://ermig.livejournal.com/164783.html</link>
  <description>Колобка судьба от зайца&lt;br /&gt;И от волка сберегла,&lt;br /&gt;Ну а с мишкой даже кепка&lt;br /&gt;Колобку не помогла...</description>
  <comments>http://ermig.livejournal.com/164783.html</comments>
  <category>отстранение от власти</category>
  <category>Колобок</category>
  <category>Лужков</category>
  <lj:security>public</lj:security>
  <lj:reply-count>0</lj:reply-count>
</item>
</channel>
</rss>

