Нетто конференций по SMM, маркетингу и диджиталу

Я, как и многие читатели ресурсов Тематических Медиа, испытываю большой интерес к последним достижениям в области информационной безопасности. Ещё со времён выхода в свет фильма «Хакеры» (и меня поймут те, кто будучи подростком застал эпоху освоения персональных компьютеров энтузиастами) я представлял себя эдаким кибер-ковбоем нового виртуального «дикого запада». Однако, вместо того, чтобы изучать технологии соответствующего профиля, я ушёл в дизайн, затем в рекламу, параллельно осваивая несложный стек веб-технологий. Единственной отдушиной несбывшейся детской мечте стало знакомство с понятием growth hacking:

image

Как вы понимаете, столь гордый титул обязывает держаться в переднем крае маркетинговой мысли. Например, какие доклады готовят специалисты по информационной безопасности для крупнейших конференций? Что-то абсолютно безумное: взлом АЭС с мобильника, перехват управления кардио-стимулятора, деанонимизация в TOR и тому подобное (если я и перегибаю, то не сильно). Захватывает дух, не правда ли? Но давайте представим, как бы выглядела конференция черношляпников, если бы её программа была составлена на манер конференций по цифровому (простите — диджитал) маркетингу:

image

Поймите меня правильно, я не хочу сказать что темы таких докладов были бы полностью бесполезны. Уверен, что человек с опытом, смог бы раскрыть неочевидные нюансы или как минимум, сделал бы своё выступление интересным и вдохновляющим. Однако, попадая на такие конференции, чувствуешь себя золотодобытчиком, просеивающим тонны песка в поисках золотой крупицы. Почему так?

Конференция — это продукт

Конференция — это продукт, и производитель нацеливается на самую широкую аудиторию. Конференции по маркетингу, пожалуй, самые рекламируемые из всех видов конференций. Доходит практически до абсурда, когда рекламу конференции по цифровому маркетингу вы встречаете в петербургском метро (если доля абсурдности такого размещения вам неочевидна или вы, например, проживаете в городе где нет метро, поясню: так рекламируют товары и услуги самого широкого потребления и преимущественно высокой рентабельности. Для Петербурга сейчас это ипотека, сотовая связь, вклады, бытовая электроника и доставка еды). А чем шире целевая аудитория, тем проще для восприятия должна быть тема доклада. Узкоспециализированный кейс может не затронуть струны души страждущих.

Производитель, так же, стремится затратить меньше усилий, с расчётом максимизировать прибыль (а значит сократить риски). Создание «контента» отдаётся на «аутсорс», и фактически, делегируется ответственность за качество. Возможные претензии, будут адресованы скорее всего докладчику, а не производителю.

Игра с нулевой суммой

Доклады конференций по информационной безопасности, так или иначе, делают мир более безопасным, подробно объясняя что именно нужно защищать в существующих системах, требуют высокой квалификации и множества других ограничений к тому, чтобы кто-то мог воспроизвести услышанное в докладе. Но что получает оратор, выступающий на конференции по маркетингу, раскрывая свои ноу-хау? Пока речь касалась традиционных видов рекламы, где было сложно воспроизвести итоговый результат, но легко попытаться скопировать сам носитель, докладчик мог сколь угодно подробно описывать процесс создания рекламы ничем не рискуя.

Давайте отмотаем время чуть вспять. Буквально за полгода-год до появления термина «морды» в среде seo-шников. Представьте, вы замечаете, что всего несколько ссылок, установленных на главных страницах сторонних сайтов на ваш, существенно поднимают вас в поисковой выдаче. Вы идете выступать на конференцию, рассказываете об этом — и тысячи довольных seo-шников тем же вечером легко повторяют ваш метод, тем самым резко девальвируя его результативность.

Конференция — это тусовка

Я как-то в разговоре с одним товарищем, имеющим опыт организации мероприятий, удивлялся тому, что конференции устраивают в будний день. На что он мне резонно возразил: «А кто будет тратить свои выходные на конфу? Гораздо приятнее отпроситься с работы на конференцию».

К конференциям теперь в довесок продают вечеринки, танцы и ужин со спикерами. Развлекательный характер всячески подчеркивается, стоит ли удивляться, что темы докладов становятся всё более «казуальными»?

Это всё о кейсах

Все ли довольны таким положением вещей? Возможно нет, иначе бы организаторы не предпринимали попыток убеждать нас в полезности их мероприятий. Волшебным словом стали «кейсы», финальным аргументом и главным поводом купить билет. Воды не будет, будут кейсы. От практикующих специалистов, а не шоуменов. Благодаря кейсам, вы сможете узнать, что кто-то, рекламируя что-то, потратил 3 рубля 80 копеек за переход и достигал конверсии в 12%, а так же стоимость размещения рекламы во влогах начинающих ютуберов. Вы всячески расширите свой кругозор, став мини-энциклопедией чьих-то прошлогодних рецептов.

Я не отрицаю полезности кейсов как таковых, но это не то понятие, от которого, словно от bluetooth, всё автоматически становится лучше. Кейсы без анализа исходных данных и полученного результата могут служить исключительно источником вдохновения (они смогли, значит и я тоже), кейсы как основа контента конференции должны быть выдающимися и актуальными, воспроизводимыми, они должны иллюстрировать главную идею доклада, а не быть его единственным содержимым.

Статистическая компетентность

Однажды меня поразил крайне интересный кейс. Представьте, вам приходит сообщение накануне футбольного матча, в котором сообщается, что победит такая-то команда. Проходит матч и вы понимаете что в сообщении победителя назвали точно. Ещё через неделю, перед очередным матчем, вы снова получаете сообщение с командой победителя. И снова, матч заканчивается с предсказанным результатом. Когда приходит время очередной игры, вам приходит предложение купить прогноз, чтобы сделать ставку.

Тем, кто с этим кейсом не знаком, объясняю. Мошенники высылают одной группе адресатов сообщение что победит команда №1, а другой группе адресатов — что команда №2. В следующий раз сообщение высылается только тем адресатам, для которых прогноз оказался верным, точно по такому же принципу. Как и итоговое предложение купить прогноз, опять же, только тем, кому оба раза достался верный прогноз.

Этим же алгоритмом можно воспользоваться и для создания фабрики экспертов. Представьте, что каждый прогноз подписывается уникальным именем-фамилией. Если он оказывается верным, один из следующих вариантов сохраняет прежнее авторство. Цепочка верных прогнозов для одного эксперта не может оказаться бесконечной, но задав некий допустимый уровень ошибок, вы сможете получить некоторое число имен-фамилий, которые будучи реальными людьми, приобрели бы авторитет футбольных экспертов. Что они смогли бы рассказать на конференции по прогнозированию результатов матчей?

Ну если бы они были помещены в соответствующую среду, будущие матчи комментировали с большой долей неопределённости, зато охотно бы обсуждали верные прогнозы на уже состоявшиеся матчи, думаю, о сути природы их чрезвычайной компетенции догадаться было бы крайне сложно.

Практические советы тем, кто идёт

Известные мне спикеры, в общей массе своей, люди с опытом, профессионалы, которых интересно послушать. Верно заданный вопрос во время доклада, может сэкономить вам время на поиск собственного решения (если оно напоминает «изобретение велосипеда») или дать верное направление. Вы так же можете получить удовольствие от остроумия спикера, от его умения находить интересные примеры или аналогии. Однако, если ожидаете практической пользы, отдавайте преимущество выступлению того спикера, который:

  • Не пишет и не продаёт книги
  • Не является владельцем или руководителем «гламурного» агенства
  • Чья тема доклада сформулирована не общими словами
  • Чья тема доклада состоит не только из buzzwords
  • Работает в аналогичной (вашей) или схожей нише
  • Может обладать инсайдами важных сервисов, платформ, приложений

О любых исключениях из этих правил, пишите в комментариях. И до встречи на конференциях 🙂

ссылка на оригинал статьи https://megamozg.ru/post/26090/

Спросите Итана №46: Что такое квантовое наблюдение


Можно увидеть многое, просто наблюдая
— Йоги Бера

Читатель спрашивает:

А что такое «наблюдение»? У меня есть два примера, которые я тем меньше понимаю, чем больше о них думаю: эксперимент Юнга и теорема Белла. Чем больше я о них думаю, тем меньше я понимаю, что на самом деле означает «наблюдение».

Давайте начнём с рассмотрения этих двух классических примеров странности квантового мира.

image

Сначала возьмём эксперимент Юнга. Давно известно, что частицы ведут себя не так, как волны. Если вы возьмёте экран с двумя щелями и будете кидать туда камушки, или пульки, или другие макроскопические предметы, большинство камушков будет задержано экраном. Несколько пролетят через щели. Можно ожидать, и по сути, так и происходит, что несколько камушков пролетят через левую щель, и несколько – через правую.

image

И у вас будут две кучки камушков, составляющих кривую в виде колокола (нормальное распределение), по одной для каждой щели. И это происходит вне зависимости от того, смотрите вы на камушки в момент броска, или нет. Побросали камушки, получили такую картинку. Всё.

А что, если у вас есть бассейн с водой, и вы с одной его стороны создаёте волны? Вы можете разместить экран с двумя щелями, чтобы волны могли проходить только через щели. В результате у вас появится два источника волн.

В результате вы получите картину интерференции, где есть пики и провалы, а также промежутки, где будет просто средняя высота воды без волн. Это называется интерференцией – иногда пики и провалы складываются и усиливают друг друга, иногда пик складывается с провалом и взаимно компенсируются.

image

Эксперимент Юнга был серией экспериментов, проводимых с 1799 по 1801 года. Через две щели светили светом, чтобы понять, будет он вести себя, как частицы, или как волны. Теперь этот стандартный эксперимент студенты повторяют в лабораториях. В результате получается такая картина:

image

Очевидно, тут происходит интерференция. Открытый в начале 1900-х фотоэлектрический эффект, согласующийся с идеей квантификации света на фотоны с разными энергиями, вроде бы говорил о том, что свет состоит из частиц, а не из волн – и всё равно он создавал такую интерференционную картину, проходя через две щели.

Дальше ещё страньше. В 1920-х физики решили провести тот же эксперимент, только с электронами вместо фотонов. Что случится, если направить поток электронов (например, от радиоактивного источника, испытывающего бета-распад) на две щели с экраном позади них? Какую картину мы увидим?

image

Как ни странно, источник электронов также даёт интерференционную картину!

«Погодите-ка»,- сказали все. «Каким-то образом электроны интерферируют с другими электронами от источника распада. Давайте-ка будем пускать их поодиночке и посмотрим, что получится на экране».

Поэтому они так и сделали, и начали смотреть, какая картинка будет вырисовываться после каждого электрона. Вот, что они увидели.

image

Получилось, что каждый электрон интерферировал сам с собой, проходя через щели! Чот и привело физиков к вопросу о том, как это происходит – раз электроны являются частицами, они могут проходить только через одну из щелей, словно камушки или пульки.

Так как же? Они сделали «ворота» (в которые можно светить фотонами, чтобы те взаимодействовали с тем, что проходит через щель), чтобы определить, через какую щель проходит каждый конкретный электрон. В результате, конечно, получилось, что электрон проходил через одну из двух щелей. Но затем, посмотрев на получающуюся картинку, они обнаружили, что она превратилась в картину, нарисованную частицами, а не волнами. Иначе говоря, электрон будто бы знал, наблюдаете вы за ним или нет!

image

Или, как говорят физики, акт наблюдения изменяет результат эксперимента. Это может показаться странным, но именно это и происходит во всех квантовых системах, организованных таким образом: всё работает так, как будто оно находится в волновой суперпозиции всех возможных результатов, но как только вы делаете ключевое «наблюдение», оно заставляет систему выдать вам один реальный ответ.

Другой пример, о котором говорит наш читатель, это квантовая запутанность.

image

Многие частицы можно создать так, что они будут находиться в запутанном состоянии: когда вы будете знать, например, что у одной должен быть положительный спин, а у другой – отрицательный (например, ±½ для электронов, ±1 для фотонов, и т.п.), но не знаете, у какой из них какой спин. Пока вы не совершите измерение, вам придётся обращаться с ними так, будто каждая частица находится в суперпозиции позитивного и негативного состояния. Но когда вы «наблюдаете» свойства одной из них, вы сразу же узнаёте о соответствующем свойстве другой.

image

Это странно – как и в случае с электронами, проходящими через щель, частицы ведут себя по разному, в зависимости от того, находятся они в суперпозиции состояний, или же их заставили принять одно из «чистых» состояний. В теории можно запутать две частицы, передвинуть одну из них на расстояние светового года, пронаблюдать первую, узнать её спин, и сразу же узнать спин другой. Вам не надо будет ждать год, чтобы сигнал пришёл к вам со скоростью света.

Если вам кажется, что это странно, то так оно и есть. Сам Эйнштейн был обескуражен этим, и решение этого, сделанное Беллом, состоит в том, что квантовая запутанность – это нелокальный феномен.

image
Если вы наблюдаете две частицы, а затем разводите их на большую дистанцию, то получаете (а). Если вы запутываете их, а затем разводите, они обе не определены, пока вы не одну из них не наблюдали (b). Но, пронаблюдав одну из них, вы тут же узнаёте состояние другой (с).

При этом тот, кто находится рядом с частицей, отодвинутой на световой год, не сможет заметить в ней никаких изменений, когда вы измерите свою. Только после того, как вы сведёте ваши частицы вместе (или передадите информацию о них, что ограничивается скоростью света), вы сможете пронаблюдать состояния обеих частиц.

Теперь можно ответит на вопрос читателя: что есть наблюдение?

image

Несмотря на то, что вы могли подумать, прочтя эти строки, наблюдение не имеет ничего общего с вами, с наблюдателем. Все разговоры про измерения и наблюдения прячут правду – чтобы произвести эти измерения, вам надо сделать так, чтобы квантовая частица взаимодействует с той, которую мы пытаемся наблюдать. И если нам нужно провести эти измерения, нам нужно, чтобы это взаимодействие прошло с определённым уровнем энергии.

Это не имеет ничего общего с вами или с «актом наблюдения», а зависит от того, провзаимодействуете ли вы с достаточной энергией для того, чтобы «сделать наблюдение», или, иначе говоря, удастся ли вам перевести частицу в одно из квантовых состояний.

image

Для электрона, проходящего сквозь щель, это означает взаимодействие с фотоном, который ограничит его позицию достаточно для того, чтобы он явно прошёл через одну из щелей. Для фотона со спином +1 или -1 это означает проведение измерения чувствительного к его поляризации, что означает взаимодействие, чувствительное к типу электромагнитного поля, создаваемого фотона.

image

Поэтому, наблюдение – это квантовое взаимодействие, достаточное для определения квантового состояния системы.

ссылка на оригинал статьи https://geektimes.ru/post/275480/

Сколько будет стоить такая задача? Вопрос программистам

Последнее время появилось очень много лжеспециалистов умников которые гонят на всех и советуют всякие сложные технологии, а по итогу делают все в 5 раз дороже и дольше, а потом с их кодом никто не хочет работать.

Встречается такое мнение: Если человек профессионал, то он может выполнить задачу быстрее, качественней и по лучшей цене.

Вопрос: Во сколько $ и времени вы бы оценили такую простую задачу и на каких технологиях сделали бы ее?

Демо-Проект: Knowledge Base

Нужен Back-End + скрипты, допустим верстка простая и уже готова

База Данных
Пользователи
Категории
Страницы (имеют категорию и отметки о просмотре )
Отметки — просмотрено

Интерфейс:

Страница входа
Вход/Регистрация/Забыли пароль
Вход через Facebook и Google+
Список информации — Главная
Лента страниц постранично
Фильтр по категории
Поиск по тексту
Поиск по НЕ прочитанному

Страница информации:
HTML контент
Кнопка “Отметить как прочитанное”

Админ панель
Вход
Таблица пользователей
Таблица категорий
Страницы (+HTML редактор)

API для моб. приложения iOS + Android:
Вход/Регистрация, Забыли пароль, Вход через соц. сети
Список информации — JSON ответ
Поиск по категории, Поиск по тексту, Поиск по НЕ прочитанному
Страница информации — отдает HTML, который вставляется в WebView
И кнопка “Отметить как прочитанное”

Дополнительно:

Мультиязычность интерфейса
Мультиязычность данных в базе
Оптимизация под нагрузки: более 1000 000 запросов в день

Что скажите? Кто бы за сколько такое запрограммил?

ссылка на оригинал статьи https://habrahabr.ru/post/283126/

Разработка компонентов (CustomControl) на WPF


Предисловие

Некоторое время назад я писал статьи о разработке компонентов на WinForms, о разработке на WPF в стиле WinForms, а теперь хочу поделиться опытом разработки компонентов на WPF, но в “стиле WPF”.
Кому интересно, прошу под кат.

Постановка задачи

Задача такая же как и прежде разработать компонент для отображения слова ДПК. Слово ДПК 32-х разрядное, состоит из адреса – 8 бит и данных – 24 бита. На рисунке показано как выглядит результат.

Выбранное решение

Для решения этой задачи я выбрал “Пользовательский настраиваемый компонент” – по терминологии Visual Studio.
Создал решение с двумя проектами:

  • Debug_WpfApplication – запускаемый проект для отладки;
  • WpfCustomControlLibrary – собственно проект с компонентом.

На рисунке представлено как это выглядит в Visual Studio.

Разбор решения

Как видно, из первого рисунка компонент слова ДПК (CustomDpkView) состоит из 4-х областей:

  • «TextBlock» Адрес;
  • Значение адреса с 1 по 8 бит (Разработанный компонент CustomBinView);
  • «TextBlock» Данные;
  • Значение данных с 9 по 32 бит (Разработанный компонент CustomBinView);

Итак, что же из себя представляют эти два компонента CustomBinView и CustomDpkView?
Поля и методы (данные и поведение) описаны в соответствующих «*.cs» файлах и графический макет (стиль) описан в файле «Generic.xaml».

Компонент CustomBinView


Рассмотрим «CustomBinView.cs».
Здесь описаны DependecyPropery и их регистрация.

Пример 1

//Значение по-умолчанию кол-ва ячеек         const int DEFAULT_CNT=8;         static CustomBinView()          {             //Переопределение стандартного стиля             DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomBinView), new FrameworkPropertyMetadata(typeof(CustomBinView)));             ArrayList temp = new ArrayList(DEFAULT_CNT);             for (int i = 0; i < DEFAULT_CNT; i++) temp.Add(true);             ValuesProperty = DependencyProperty.Register("Values", typeof(ArrayList), typeof(CustomBinView), new FrameworkPropertyMetadata(temp, new PropertyChangedCallback(InvalidateVisualCallback)));             FirstNumberProperty = DependencyProperty.Register("FirstNumber", typeof(int), typeof(CustomBinView), new FrameworkPropertyMetadata(new PropertyChangedCallback(InvalidateVisualCallback)));             ColorTrueProperty = DependencyProperty.Register("ColorTrue", typeof(Brush), typeof(CustomBinView), new FrameworkPropertyMetadata(new PropertyChangedCallback(InvalidateVisualCallback)));             ColorFalseProperty = DependencyProperty.Register("ColorFalse", typeof(Brush), typeof(CustomBinView), new FrameworkPropertyMetadata(new PropertyChangedCallback(InvalidateVisualCallback)));             IsVisibleTextProperty = DependencyProperty.Register("IsVisibleText", typeof(bool), typeof(CustomBinView), new FrameworkPropertyMetadata(new PropertyChangedCallback(InvalidateVisualCallback)));         }         //При изменении свойств, влияющих на визуальный вид - перерисовывать компонент         private static void InvalidateVisualCallback(DependencyObject sender, DependencyPropertyChangedEventArgs e) { ((CustomBinView)sender).InvalidateVisual(); }         //------------------------------------------------------------------------------------------//         #region DependencyProperty и их регистрация             public static DependencyProperty ValuesProperty;             public static DependencyProperty FirstNumberProperty;             public static DependencyProperty ColorTrueProperty;             public static DependencyProperty ColorFalseProperty;             public static DependencyProperty IsVisibleTextProperty;               #endregion         //------------------------------------------------------------------------------------------//         #region Свойства доступа к значениям DependencyProperty             //Ячейки со значениями             public ArrayList Values { get { return (ArrayList)GetValue(ValuesProperty); } set { SetValue(ValuesProperty, value); } }             //Номер, с которого будут считаться ячейки             public int FirstNumber { get { return (int)GetValue(FirstNumberProperty); } set { SetValue(FirstNumberProperty, value); } }             //Цвет true-значения             public Brush ColorTrue { get { return (Brush)GetValue(ColorTrueProperty); } set { SetValue(ColorTrueProperty, value); } }             //цвет false-значения             public Brush ColorFalse { get { return (Brush)GetValue(ColorFalseProperty); } set { SetValue(ColorFalseProperty, value); } }             //Признак отображения текста в ячейках             public bool IsVisibleText { get { return (bool)GetValue(IsVisibleTextProperty); } set { SetValue(IsVisibleTextProperty, value); } }          #endregion 

Ниже описана реализация рендеринга и алгоритма клика по ячейкам.

Пример 2

protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)         {//при изменении размеров перерисовывать содержимое             base.OnRenderSizeChanged(sizeInfo);             InvalidateVisual();         }         protected override void OnRender(DrawingContext drawingContext)         {             base.OnRender(drawingContext);             DrawingContext dc = drawingContext;             //Отрисовка фона и гриниц             dc.DrawRectangle(Background, null, new Rect(new Point(0, 0), RenderSize));             #region Расчёт размеров и проверка условий                 if ((Values == null) || (Values.Count == 0)) return;                 double FullWidthCell = RenderSize.Width / (double)(Values.Count);                 double WidthCell = FullWidthCell;                 double HeightCell = RenderSize.Height;                 if ((WidthCell > 2) && (HeightCell > 2)) { WidthCell -= 2; HeightCell -= 2; }              #endregion             #region Отрисовка ячеек                 //Текущий номер ячейки, который будет рисоваться в ячейке                 int currentNumber = FirstNumber;                 //точка-указатель на текущую рисующуюся ячейку                  Point currentPointCell = new Point(1, 1);                 //Размер длины окургления ячейки                 double roundedLenght = ((0.15 * WidthCell) > (0.15 * HeightCell)) ? (0.15 * HeightCell) : (0.15 * WidthCell);                 foreach (bool item in Values)//отрисовка всех ячеек                 {                     //отрисовка прямоугольника ячейки с фоном                     dc.DrawRoundedRectangle((item) ? ColorTrue : ColorFalse, new Pen(BorderBrush, 1),                         new Rect(currentPointCell, new Size(WidthCell, HeightCell)),                         roundedLenght, roundedLenght);                     //отрисовка текста ячейки                     if (IsVisibleText)                          Service.DrawTxt(dc, currentNumber.ToString().PadLeft(2, '0'), currentPointCell, new Size(WidthCell, HeightCell),                              Foreground, this.FontFamily, this.FontStyle, this.FontWeight);                     //переход к следующей ячейке                     currentPointCell.X += FullWidthCell;                     currentNumber++;                 }              #endregion             }         #region Маршрутизируемое событие "Клик по элементу"             //Класс с аргументами для события             public class ClickItemRoutedEventArgs : RoutedEventArgs             {                 //Индекс элемента (нумерация с 0)                 public int Index { get; protected set; }                 //Сам элемент                 public object Item { get; protected set; }                 //Информация о клике мыши                 public MouseButtonEventArgs MouseEventArg { get; protected set; }                 public ClickItemRoutedEventArgs(RoutedEvent routedEvent, object item, int index, MouseButtonEventArgs arg)                     : base(routedEvent) { Item = item; Index = index; MouseEventArg = arg; }                 public ClickItemRoutedEventArgs()                     : base() { Item = null; Index = -1; MouseEventArg = null; }             }             //Регистрация события             public static readonly RoutedEvent ClickItemEvent = EventManager.RegisterRoutedEvent("ClickItem", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(CustomBinView));             //Контейнер добавления-удаления подписчиков             public event RoutedEventHandler ClickItem             {                 add { base.AddHandler(ClickItemEvent, value); }                 remove { base.RemoveHandler(ClickItemEvent, value); }             }             //Функция генерации события             void RaiseClickItem(object item, int index, MouseButtonEventArgs arg)             {                 ClickItemRoutedEventArgs args = new ClickItemRoutedEventArgs(ClickItemEvent, item, index, arg);                 RaiseEvent(args);             }         #endregion         protected override void OnMouseUp(MouseButtonEventArgs e)//Клик мышкой по контролу         {             base.OnMouseUp(e);             #region Расчёт размеров и проверка условий                 if ((Values == null) || (Values.Count == 0)) return;                 double FullWidthCell = RenderSize.Width / (double)(Values.Count);                 double WidthCell = FullWidthCell;                 double HeightCell = RenderSize.Height;                 if ((WidthCell > 2) && (HeightCell > 2)) { WidthCell -= 2; HeightCell -= 2; }                 Point currentPointCell = new Point(1, 1);              #endregion             for (int currentNumber = 0; currentNumber < Values.Count; currentNumber++, currentPointCell.X += FullWidthCell)             {                 //Проверка попадания по ячейке                 if (new Rect(currentPointCell, new Size(WidthCell, HeightCell)).Contains(e.GetPosition(this)))                 {                     Values[currentNumber] = !(bool)Values[currentNumber];//ИНверсия значения                     this.InvalidateVisual();//Вызов рендеринга                     RaiseClickItem(Values[currentNumber], currentNumber, e);//Генерация события клика                 }             }         } 

Теперь рассмотрим «Generic.xaml». Здесь описан визуальный стиль (макет) компонента.

Пример 3

    <!--Стиль CustomBinView-->     <Style TargetType="{x:Type local:CustomBinView}">         <!--Стиль оформления для компонента CustomBinView         Задание соответствующим полям в CustomBinView.cs значения по-умолчанию-->         <Setter Property="FirstNumber" Value="1"/>         <Setter Property="ColorTrue">             <Setter.Value>                 <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">                     <GradientStop Color="WhiteSmoke" Offset="0" />                     <GradientStop Color="Red" Offset="1" />                 </LinearGradientBrush>             </Setter.Value>         </Setter>         <Setter Property="ColorFalse">             <Setter.Value>                 <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">                     <GradientStop Color="WhiteSmoke" Offset="0" />                     <GradientStop Color="Gray" Offset="1" />                 </LinearGradientBrush>             </Setter.Value>         </Setter>         <Setter Property="BorderBrush" Value="Black" />         <Setter Property="IsVisibleText" Value="True"/>         <Setter Property="FontFamily" Value="Courier New"/>         <Setter Property="FontStyle" Value="Normal"/>         <Setter Property="FontWeight" Value="Normal"/>         <Setter Property="MinHeight" Value="20"/>         <Setter Property="MinWidth" Value="50"/>     </Style> 

Компонент CustomDpkView

Рассмотрим «CustomDpkView.cs». Здесь описаны DependencyProperty и их регистрация.

Пример 4

public class CustomDpkView : Control     {         public static DependencyProperty ValuesADRProperty;          public static DependencyProperty ValuesDATAProperty;         public static DependencyProperty ColorTrueProperty;         public static DependencyProperty ColorFalseProperty;         public const int CNT_ADR_BIT = 8;//Кол-во бит в поле адрес ДПК         public const int CNT_DATA_BIT = 24;//Кол-во бит в поле данные         static CustomDpkView()         {             DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomDpkView), new FrameworkPropertyMetadata(typeof(CustomDpkView)));             #region Регистрация и инициализация ValuesADRProperty                 ArrayList temp = new ArrayList(CNT_ADR_BIT);                 for (int i = 0; i < CNT_ADR_BIT; i++) temp.Add(true);                 ValuesADRProperty = DependencyProperty.Register("ValuesADR", typeof(ArrayList), typeof(CustomDpkView), new PropertyMetadata(temp));              #endregion             #region Регистрация и инициализация ValuesDATAProperty                 temp = new ArrayList(24);                 for (int i = 0; i < 24; i++) temp.Add(true);                 ValuesDATAProperty = DependencyProperty.Register("ValuesDATA", typeof(ArrayList), typeof(CustomDpkView), new PropertyMetadata(temp));              #endregion             ColorTrueProperty = DependencyProperty.Register("ColorTrue", typeof(Brush), typeof(CustomDpkView));             ColorFalseProperty = DependencyProperty.Register("ColorFalse", typeof(Brush), typeof(CustomDpkView));                     }         //Значения бит в поле Адрес (8 бит)         public ArrayList ValuesADR { get { return (ArrayList)GetValue(ValuesADRProperty); } protected set { SetValue(ValuesADRProperty, value); } }         //Значения бит в поле ДАнные (24 бита)         public ArrayList ValuesDATA { get { return (ArrayList)GetValue(ValuesDATAProperty); } protected set { SetValue(ValuesDATAProperty, value); } }         //Цвет true - значения         public Brush ColorTrue { get { return (Brush)GetValue(ColorTrueProperty); } set { SetValue(ColorTrueProperty, value); } }         //Цвет false - значения         public Brush ColorFalse { get { return (Brush)GetValue(ColorFalseProperty); } set { SetValue(ColorFalseProperty, value); } }         #region Программное задание адреса и данных             public bool SetValuesADR(ArrayList array)             {                 if (array.Count != CNT_ADR_BIT) return false;                 ValuesADR = array;                 return true;             }             public bool SetValuesDATA(ArrayList array)             {                 if (array.Count != CNT_DATA_BIT) return false;                 ValuesDATA = array;                 return true;             }         #endregion     } 

Теперь рассмотрим «Generic.xaml». Здесь описан визуальный стиль (макет) компонента, его строение.

Пример 5

<!--Стиль CustomDpkView-->     <Style TargetType="TextBlock" x:Key="labelStyle"><!--Стиль оформления для текстовых полей адрес и данные-->         <Setter Property="TextAlignment" Value="Center"/>         <Setter Property="FontFamily" Value="Comic Sans MS"/>         <Setter Property="FontWeight" Value="Bold"/>         <Setter Property="FontSize" Value="20"/>     </Style>          <Style TargetType="{x:Type local:CustomDpkView}"><!--Стиль оформления для компонента CustomDpkView-->         <Setter Property="Template">             <Setter.Value><!--Структура компонента-->                 <ControlTemplate TargetType="{x:Type local:CustomDpkView}">                     <Grid>                         <Grid.RowDefinitions><!--Разделение на 4 области (со звёздочкой - плавающее, без - постоянное)-->                             <RowDefinition Height="30" />                             <RowDefinition Height="30*" MinHeight="30" />                             <RowDefinition Height="30" />                             <RowDefinition Height="30*" MinHeight="30"/>                         </Grid.RowDefinitions>                         <!--Текстовое поле Адрес-->                         <TextBlock Style="{StaticResource labelStyle}" Grid.Row="0" Text="Адрес:"/>                         <!--Двоичное значение поля Адрес-->                         <!--Связка полей с помощью TemplateBinding                         в CustomDpkView.cs с полями компонента CustomBinView-->                         <local:CustomBinView FirstNumber="1" Grid.Row="1"                                               ColorTrue="{TemplateBinding ColorTrue}"                                               ColorFalse="{TemplateBinding ColorFalse}"                                                Values="{TemplateBinding ValuesADR}"/>                         <!--Текстовое поле Данные-->                         <TextBlock Style="{StaticResource labelStyle}" Grid.Row="2" Text="Данные:"/>                         <!--Двоичное значение поля Данные-->                         <!--Связка полей с помощью TemplateBinding                         в CustomDpkView.cs с полями компонента CustomBinView-->                         <local:CustomBinView FirstNumber="9" Grid.Row="3"                                               ColorTrue="{TemplateBinding ColorTrue}"                                              ColorFalse="{TemplateBinding ColorFalse}"                                               Values="{TemplateBinding ValuesDATA}"/>                     </Grid>                 </ControlTemplate>             </Setter.Value>         </Setter>         <!--Значение по-умолчанию для поля в CustomDpkView.cs-->         <Setter Property="ColorTrue">             <Setter.Value>                 <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">                     <GradientStop Color="WhiteSmoke" Offset="0" />                     <GradientStop Color="Red" Offset="1" />                 </LinearGradientBrush>             </Setter.Value>         </Setter>         <!--Значение по-умолчанию для поля в CustomDpkView.cs-->         <Setter Property="ColorFalse">             <Setter.Value>                 <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">                     <GradientStop Color="WhiteSmoke" Offset="0" />                     <GradientStop Color="Gray" Offset="1" />                 </LinearGradientBrush>             </Setter.Value>         </Setter>     </Style> 

Использование этих компонентов в Debug_WpfApplication

Рассмотрим «Main.xaml».

Пример 6

<Window.Resources> <!-- Стиль для customDpkView1 -->         <Style TargetType="{x:Type ccl:CustomDpkView}" x:Key="dpkViewStyle_1">             <Setter Property="ColorTrue">                 <Setter.Value>                     <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">                         <GradientStop Color="WhiteSmoke" Offset="0" />                         <GradientStop Color="Yellow" Offset="1" />                     </LinearGradientBrush>                 </Setter.Value>             </Setter>             <Setter Property="ColorFalse">                 <Setter.Value>                     <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">                         <GradientStop Color="Gray" Offset="0" />                         <GradientStop Color="White" Offset="1" />                     </LinearGradientBrush>                 </Setter.Value>             </Setter>         </Style>     </Window.Resources>     <Grid>         <Grid.RowDefinitions>             <RowDefinition Height="114" />             <RowDefinition MinHeight="50" Height="114*" />             <RowDefinition Height="50" />         </Grid.RowDefinitions>         <ccl:CustomBinView  Name="customBinView1" Margin="12,12,12,20" /> <!-- CustomDpkView с пользовательским стилем -->         <ccl:CustomDpkView Style="{StaticResource dpkViewStyle_1}" Name="customDpkView1" Grid.Row="1" Height="174" VerticalAlignment="Top" Margin="12,0" />         <TextBlock Name="textBlock1" Text="TextBlock" Grid.Row="2" TextAlignment="Center" FontStretch="Normal" FontFamily="Comic Sans MS" FontWeight="Bold" FontSize="20" Margin="0,0,429,0" />         <Button Content="Button" Grid.Row="2" Name="button1" HorizontalAlignment="Right" Width="75" Click="button1_Click" /> <!-- CustomDpkView со стилем по-умолчанию -->         <ccl:CustomDpkView Grid.Row="1" Margin="12,180,12,0" Name="customDpkView2" VerticalAlignment="Top" Height="133" />     </Grid> 

P.S.

Ссылка на проект: Скачать проект
Примечание: разработка велась в MS Visual Studio 2010 под «.Net Framework 4»
Жду комментариев и дополнений.

ссылка на оригинал статьи https://habrahabr.ru/post/283124/

Щелевая съёмка: реализация на bash (ffmpeg + imagemagick)

Не помню что и почему я искал в интернете несколько дней назад, но я наткнулся на интересную статью с необычными фотографиями. А позже на еще одну статью, где описывалась реализация алгоритма создания таких фотографий на python. После прочтения меня заинтересовала эта тема и я решил провести вечера майских праздников с пользой для себя, а именно реализовать алгоритм «конвертирования» видео в щелевое фото. Правда, не на питоне, но подручными средствами на bash’е. Но обо всем по порядку.

Что такое щелевое фото

Вид фотографии, на которой запечатлено не одно событие в один конкретный момент времени, а несколько событий. Это достигается за счет того, что щелевая камера снимает кадры шириной в один пиксель (это и есть «щель») и «склеивает» их в одно фото. Немного запутанно звучит и пока сложно представить, что это такое и как выглядит. Самым доходчивым объяснением для меня был комментарий к одной из вышеупомянутых статей от пользователя Stdit:
image
После этого все становится понятным.

Пример для наглядности
image
Смотря на это фото можно сделать вывод, что первый слева легковой автомобиль сначала стоял неподвижно, а потом начал двигаться.

Алгоритм построения щелевой фотографии

  1. Разложить видео на множество изображений.
  2. Обрезать каждое полученное изображение по ширине в один пиксель с заданным смещением (щелью).
  3. Собрать полученное множество изображений в одно.

Звучит нестрашно и просто.

Дано

  • Камера Xiaomi Yi
  • Желание разобраться и сделать несколько необычных фото
  • Пару вечеров свободного времени
Решение

Первое и самое простое, что приходит на ум, это написать bash скрипт, который будет обрабатывать видео и фото в соответствии с описанными шагами алгоритма. Для реализации задуманного мне понадобился ffmpeg и imagemagick. В упрощенном виде на псевдо bash скрипт выглядит так:

ffmpeg -i videoFile frame-%d.png  for ((i = 1; i <= framesCount; i++)); do   convert -crop 1xframeHeight+slitShift+0 frame-$i.png slit-$i.png done  montage slit-%d.png[1-framesCount] -tile framesCountx1 -geometry +0+0 outputImage 
Разберемся что здесь происходит

  • Во-первых, с помощью утилиты ffmpeg разбиваем видео на множество изображений вида frame-0.png…frame-n.png.
  • Во-вторых, с помощью утилиты convert из пакета imagemagick обрезаем каждое полученное изображение (ключ -crop) следующим образом: ширина == 1px, высота == высоте изображения. Так же указываем смещение щели по горизонтали. Сохраняем в файлы вида slit-0.png…slit-n.png.
  • В-третьих, с помощью утилиты montage из пакета imagemagick собираем полученные изображения в одно фото. Ключ -tile указывает на то, что все фото нужно собрать в одно по шаблону «framesCount по горизонтали и 1 по вертикали», то есть собрать множество изображений в один ряд.
Результат

За пару вечеров был написан скрипт, которому на вход подаем видео файл, а на выходе получаем фотографию. В теории на вход можно подавать видео в любом формате, который поддерживает ffmpeg. Выходной файл можно получить в тех форматах, которые поддерживает imagemagick.

Пользоваться скриптом очень просто:
./slitcamera.sh --input=test.avi --output=test.png --slit-shift=100

где input — видео файл для обработки, output — название результирующего файла, slit-shift — смещение щели по горизонтали.

Первым делом для быстрого тестирования я не стал снимать видео на камеру, а скачал первое попавшееся видео с youtube и «скормил» его скрипту. Вот что из этого вышло:

На следующий день с собой на прогулку я взял свою Xiaomi Yi и снял несколько видео. Вот что из этого вышло.

Родное Азовское море (фото сделано из видео разрешением в 1920×1080 пикселей и продолжительностью в 31 секунду, 60к/с)


А эти фото собраны из видео разрешением в 1280×720 пикселей и продолжительностью в 16 секунд, 120к/с. Обратите внимание на фон второго фото. Он не статичен. На фоне было движущееся колесо обозрения.

Посмотреть и скачать скрипт можно в моем репозитории на GitHub. Предложения, критика и пулреквесты только приветствуются.

ссылка на оригинал статьи https://habrahabr.ru/post/283120/