Показаны сообщения с ярлыком программирование. Показать все сообщения
Показаны сообщения с ярлыком программирование. Показать все сообщения

среда, 3 октября 2012 г.

Python+OpenCv распознавание лиц и определение расстояния до них (версия простая )

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


Мы живём в счастливую для лентяев эпоху - вам уже не нужно купаться в сложной математической теории. Всё сделано за вас, по крайней мере на таком элементарном уровне. Распознавание лиц происходит по признакам Хаара. "Эталон" лица уже давно создан и хорошо обучен, находится он в файле haarcascade_frontalface_alt.xml . Там находится, так называемая, модель лица, а именно "Идеальное" лицо в виде примитивов Хаара :

Это бинаризированая диаграмма яркостей. У любого лица посередине светло(нос), а по краям уходит в тёмное, а потом снова на светлое( щеки). Таких признаков у лица много, и они перечислены в haarcascade_frontalface_alt.xml. А наша программка будет их искать.

 Первый бой (вывод видео на экран) :

  Для начала давайте на экран выведем видео поток. С помощью OpenCV это делается элементарно.




import cv2

cam = cv2.VideoCapture(0)
while 1:
     _,frame =cam.read()
     cv2.imshow("features", frame)
     if cv2.waitKey(10) == 0x1b: # ESC
         print 'ESC pressed. Exiting ...'
         break

Работает? Классно!
Код прост:
Я создаю объект камеры, которая подхватит первую попавшуюся(ваша web-ка)
И всё последующее время я буду читать 1 кадр из камеры и выводить его на экран, каждые десять миллисекунд опрашивать клавиатуру, и, если нажата клавиша с кодом 27(Esc) ,то выйду из бесконечного цикла прямо в ОС.



Битва вторая( использование микроскопа по назначению):

Использовать OpenCV для вывода видео на экран - забивание гвоздей микроскопом. Не будем столь брутальны - начнём  распознавание лиц:



import sys
import cv,cv2
import numpy
cascade = cv.Load('haarcascade_frontalface_alt.xml')

def detect(image):
 bitmap = cv.fromarray(image)
 faces = cv.HaarDetectObjects(bitmap, cascade, cv.CreateMemStorage(0))
 if faces:
  for (x,y,w,h),n in faces:
   pass
   cv2.rectangle(image,(x,y),(x+w,y+h),(255,255,255),2)
 return image

if __name__ == "__main__":
    cam = cv2.VideoCapture(0)
    while 1:
        _,frame =cam.read()
        frame = numpy.asarray(detect(frame))
        cv2.imshow("features", frame)
        if cv2.waitKey(10) == 0x1b: # ESC
            print 'ESC pressed. Exiting ...'
            break

HaarDetectObjects принимает 3 параметра ( где_искать,что искать, где_хранить_промежуточные_данные)
где_хранить_промежуточные_данные - область памяти, которую можно выделить функцией CreateMemStorage.

Уже что-то.

Последний бой ( проявите каплю своего творчества):

Если, проделав это всё, вы гордо скажите, что вы программист, я плюну вам в лицо. Что вы сделали? Ну хоть малость своих мыслей тут? Мы использовали стандартные функции для совершения достаточно тривиальных действий - ни капли математического аппарата. Давайте-же прибавим! А что тут можно сделать? Определим расстояние до лица!
Попытаемся понять, как работает наша камера:



Обратите внимание, что треугольники ACB и DCE подобны. Что это значит?
Уберём из рисунка лишнее и добавим необходимое:

А значит это то , что отношение DE/CH равно отношению AB/FC. Поднеся линейку в 10 сантиметров к веб-камере так, чтоб она поместилась полностью, и измерив расстояние до веб-камеры от линейки, мы можем узнать отношение высоты матрицы нашей камеры к её фокусному расстоянию.( у меня это 1.6) .
Средняя высота лица человека - 15 сантиметров.


Получив из OpenCV размер квадрата лица, просто вычислить, сколько процентов всей высоты кадра оно занимает. Несложно додуматься, что Если лицо влезает в камеру всеми своими 15 сантиметрами , то до веб-камеры - (AB/FC)*12. Если лицо занимает меньше 100% пространства, то оно более удалено. Давайте определим , насколько...





Из рисунка видно, что переместив объект из точек CD в точки EF, его отображение(GH) будет занимать не 100% , а N%(где N<=100). Из свойства подобия треугольников видно, что отношение GH/AB = KL/CD. А ,значит, для наглядности ,я могу упростить модель до треугольника и трапеции:
Что нам отсюда известно?
Мы знаем, отношение AB/FE - это есть наше фокальное расстояние, обозначим его как focal.
реальные размеры AB.

Нам надо узнать расстояние FG.
Треугольники AFB и DFC подобны, значит FE/FG=AB/DC. Из этого равенства видно, что если FG увеличивается в M раз, то либо DC увеличивается в M раз, либо AB уменьшается в M раз. AB уменьшится не может - это реальный размер лица, он всегда 15 сантиметров, А вот DC - может, это размер лица на фотографии, чем лицо дальше, тем размер его меньше. Исходя из этого, можно сделать вывод, что если DC уменьшилось в M раз( или на N%) ,то и FG уменьшилось так же в M раз( или на N%). Если DC у нас равно AB, то GF = EF, если DC меньше AB в M раз (илиN%),то и FG


Теперь ближе к коду:

import sys
import cv,cv2
import numpy
cascade = cv.Load('haarcascade_frontalface_alt.xml')
c=1.6
Sr=15

def detect(image):
 bitmap = cv.fromarray(image)
 faces = cv.HaarDetectObjects(bitmap, cascade, cv.CreateMemStorage(0))
 if faces:
  for (x,y,w,h),n in faces:  
   k=float(w)/bitmap.cols
   S = Sr*c/k
   cv2.rectangle(image,(x,y),(x+w,y+h),(255,255,255),3)
   cv2.putText(image,'S=%s'%(S),(x,y-10), cv2.FONT_HERSHEY_PLAIN, 1.0,(255,255,255))
 return image

if __name__ == "__main__":
    cam = cv2.VideoCapture(0)
    while 1:
        _,frame =cam.read()
        frame = numpy.asarray(detect(frame))
        cv2.imshow("features", frame)
        if cv2.waitKey(1) == 0x1b: # ESC
            print 'ESC pressed. Exiting ...'
            break





Как видите, я задаю отношение размера матрицы к фокальному расстоянию и размер лица человека, и, исходя из этого, считаю его удалённость, в зависимости от процентов занимаемого им места на экране.

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

Читать дальше......

четверг, 29 марта 2012 г.

Значение-ссылка-значение-указатель C++

Как распределена память компьютера? Как мы работаем с переменными? Что такое объект, зачем нам ссылки на него?
Все это вопиет с небес на землю
И ждет разбора.
И его найдет.


Все мы знаем, ЧТо такое ссылка на объект, и что такое сам объект. Когда мы только начинали нежно прикасаться к C++. Мы недоумевали разницы между "->"и ".". Почему иногда надо то а иногда то.
Это конечно от того что мы смело кинулись писать в Здоровилах типа RAD Studio Professional, VisualStudio Ultimate ,Qt4. Где можно начать писать буквально мышкой, и имея некие представления о синтаксисе, уча его по ходу чтения кучи namespase-ов классов, непонятных define-ов typedef-ов enum-ов tamplate-ов и прочих вкусностей C++. и не прочитав ни одной страницы книги по C++ мы уже писали более не менее сложные программки. По ходу дела учась и объектно-ориентированному, и клиент-серверному,осваивая синтаксис в процессе разгребания n-ной сотни error-ов компилятора.

В хороших традициях надо начинать с простых программ, консольных, небольших, на чистом ANSI C.Постепенно в него вкрапляя С++. Например с gcc и g++;

И вот хочу сейчас продемонстрировать Что такое объект, а что такое ссылка.

Для начала освоим такие операторы..
*,&

Что они делают?

Ну сначала вспомним, как мы создаём любой объект

class A{};
 
A*Obj = new A(); 

Да, и что мы получили?
*Obj - ссылка, определяющая начало той области памяти, где находиться объект.
Оператор * возвращает копию области памяти на которой находиться объект.

Оператор & возвращает ссылку на объект
то есть &Obj будет типа **A.


Давайте, посмотри пример в котором я постарался показать как изменяются значения, если использовать ссылки и сами объекты.

#include <string>
#include <iostream>
using namespace std;
 
 
#define BallLink The_Ball*
 
 
struct The_Ball{
 string Color;
};
 
 
 
void Paint_in_Pink(The_Ball* Ball){
Ball->Color = "Pink";
}
 
void Paint_in_Gray(The_Ball Ball){
Ball.Color = "Gray";
}
 
void Paint_in_Yellow(The_Ball& Ball){
Ball.Color = "Yelow";
}
 
int main() {
 The_Ball b1;
 b1.Color = "Red";
 BallLink b1Num = &b1;
 cout<<"b1 = "<<b1.Color<<"; Adress of b1 = "<<b1Num<<"; Value got by Adress = "<<b1Num->Color<<endl;
 b1.Color = " blue";
 cout<<"b1 ="<<b1.Color<<";Adress of b1 = "<<b1Num<<" ;Value got by Adress"<<b1Num->Color<<endl;
 The_Ball b2 = b1;
 b2.Color = "Red";
 
 cout<<"b1= "<<b1.Color<<";b2 = "<<b2.Color<<endl;
 BallLink b3Num = b1Num;
 The_Ball b3 = *b3Num;
 b1.Color = "Green";
 cout<<"b3 = "<<b3.Color<<"; Value got by adress b3Num thas the same as b1Num ="<<b3Num->Color<<endl;
 b1.Color = "Black";
 b2.Color = "Black";
 b3.Color = "Black";
 cout<<"Swich all to Black"<<endl;
 Paint_in_Pink(&b1);
 Paint_in_Gray(b2);
 Paint_in_Yellow(b3);
 cout<<"b1 = "<<b1.Color<<endl;
 cout<<"b2 = "<<b2.Color<<endl;
 cout<<"b3 = "<<b3.Color<<endl;
 
}
 

И вывод
b1 = Red; Adress of b1 = 0x7fffc1b84e70; Value got by Adress = Red
b1 = blue;Adress of b1 = 0x7fffc1b84e70 ;Value got by Adress blue
b1=  blue;b2 = Red
b3 =  blue; Value got by adress b3Num thas the same as b1Num =Green
Swich all to Black
b1 = Pink
b2 = Black
b3 = Yelow
 

Начнём.
Я объявил структуру The_Ball у которой есть поле color.
И определил макрос BallLink как указатель

В первых строках main я создаю Красный мячик и ссылку на него

Дальше по значению меняю цвет на синий. После изменений, ссылка тоже указывает на теперь синий мячик.
Потом я создаю второй мячик как КОПИЮ 1-го. И меняю его цвет на Красный. И получается что 1-й у меня остаётся Синим, а второй красным. Потом я создаю ещё одну ссылку b3Num которая указывает тот-же адрес что и ссылка на 1 мячик, и создаю объект по этой ссылке, И этот объект у меня получается копия 1-го мячика, но ссылка указывает на 1-й.И при изменении цвета 1-го мячика на Зелёный, ссылка b3Num указывает уже на Зелёный цвет, когда объект созданный по ссылке, указывает на Красный.
И вот время перекрасить все объекты в Чёрный для определения. Если бы я вывел все ссылки, вы бы убедились что они тоже все обязательно указывают на Чёрное.
И теперь время вызывать функции в первую функцию Я передаю указатель на переменную, которую функция окрасит в Розовый. Во вторую Я передаю саму переменную, и в третью адресс переменной.
И что мы вилим на выходе? когда передаём ссылку, всё краситься, когда передаём саму переменную, ничего не происходит, потому что по сути мы передали копию переменной. И когда передаём ардесс переменной всё тоже хорошо красится. Вот и вся магия.Это стоит запомнить, когда буем сообщать функциям переменные которые стоит менять и не стоит менять.

Читать дальше......

среда, 29 февраля 2012 г.

Автоматическая смена обоев Linux(или опять свой велосипед)

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

На самом деле, к обоям на рабочий стол я отношусь мягко так сказать, нейтрально. Я в принципе к окружению отношусь нейтрально. Важна юзабельность, всякие Альт-табы, большая рабочая область экрана, несколько рабочих столов. Мой глаз не должно беспокоить ничего кроме среды разработки, часов, индикатора батареи, и индикатора раскладки клавиатуры, а на другом рабочем столе должен быть браузер с доками(мечтаю о 2-х мониторах). Но вот вдруг захотелось динамики. И решил написать. Заодно подучить баш. Это было полезно. Я узнал о таких командах как find ,tr, shuf
,пощупал конструкции циклов, условий, помацал работу с переменными в bash, ну и самое развратное это я можно сказать вошел в регулярные выражения. Пусть пока не особо глубоко вошел, но достаточно для выбора файлов с нерусскими названиями, без пробелов, оканчивающихся на .jpg(png,gif...), надеюсь наши отношения с продлятся ещё долго, пусть не регулярно но я хочу их познать в разных позициях.
Собственно, первый велосипед был очень громоздок и некрасив, потом я постепенно его довёл до более не менее состояния.
вышло вот что:

#!/bin/bash 

pre="file:"
florder="/media/Files/Media/Media_mix/Photo/wallpaper/"
time=20

pic(){
  pic=`ls $florder |grep '\(png\|gif\|jpg\|jpeg\)$'|shuf -n 1`
  GSETTINGS_BACKEND=dconf gsettings set org.gnome.desktop.background picture-uri ${pre}${florder}${pic}
  sleep $time
}

i=0
while [ ""-z ]
do
 pic
done

Смысл прост. Скрипт выбирает случайную картинку и каждые time раз меняет на следующую случайную в папке florder

чтоб оно работало надо его сохранить в файл типа *.sh раздать ему права на выполнение chmod +x путь_к_скрипту и прописать его выполнение в профайле пользователя $HOME/.profile или в .xinitrc(так кошерней).

Ну вот. Как я уже писал способ не единственный, один из кажущихся мне кошерными это создание xml документа с путями картинок( если не знали, то в гноме можно ставить на рабочий стол xml документ, с путями и он будет работать как анимация) подробнее про это http://linuxforum.ru/viewtopic.php?id=4591.
У меня планы создать python\qt\java программу, которая будет из выбранных пользователем изображений создавать xml документ, всё красиво с блэкджеком и шлюхами, задержками и прочим. Есть проблема в создании блэкджека и шлюх, потому что просто выбирать папку и строить xml по ней легко, но хочется Ui с красивой настройкой анимации, выставление параметров задержек, порядка фотографий и прочего. Концепция в голове, реализация красивого и серьёзного UI это ещё проблема, но будем расти :-)

Читать дальше......

четверг, 12 января 2012 г.

The Matrix

Давно я сюда ничего не писал. Всё времени формулировать мысли нет. но вот сдал все экзамены и всё-же решил опубликовать то что написал в ночи перед экзаменами. Матрица.


Есть сотни реализаций, на разных языках и графика и консоль, что хочешь. Но свой велосипед всегда приятнее.

Подробности под катом.



К тому-же сессия, надо учить экономику а она в голову не лезет. И тут я вспомнил что на С++ писал только с помощью Qt. Решил что это не порядок. Почему бы не написать что-то например с помощью gcc? В моём случае g++. И попутно изучить редактор emacs. Флаг в руки и в атаку. Решил написать заставку из матрицы. Для позиционирования символов использовал ncurses. Ещё хочеться использовать свой i5 на полную катушку. Поэтому решил сделать матрицу ещё и многопоточной. Использовал pthread.

Давайте рассмотрим костыли.
ncurses поста в использовании google кишит ссылками на эту тему. Алгоритм рисования одной пробегающей "змейки" в матрице тоже достаточно прост.



void print_snake(int col,int len,int speed){
//print 1 snake in col column with len length and speed speed;
    int i;
    for (i = 0;i<count_row;i  ){
 TS_print_char(i,col);
 if (i>=len){
            TS_print_pass(i-len,col);// when snake is almost on screen is time to clear her tail
 }
 usleep(speed);
    }
    for (i=count_row-len-1;i<count_row;i  ){
        TS_print_pass(i,col);//clear tail when snake is under screen border
 usleep(speed);
    }
}

TS_print_char - моя потоко-безопасная функция вывода случайного символа на экран в место x y.

Сначала я делал refresh каждый раз при выводе символа. Но посмотрел что програмка при выполнении занимает полтора процессора. и Ужаснулся. Вывел обновление в отдельный поток, с периодом в 10000 микросекунд. Теперь программка занимает каких-то 15 - 20 % процессора, и это при полном экране ( более 100 потоков) . Ах я ещё не говорил. Количество потоков зависит от количества столбцов помещающихся на консоль. Вот собственно и всё.

Просмотреть код можно тут:
КОД
скачать запустить, или скомпилировать и запустить можно от сюда
git clone git@github.com:alexkutsan/The-Matrix.git
или

Код легко читаем. Разобраться в нём - раз плюнуть. Я старался максимально снабдить комментариями

Матрица - хорошее упражнение. Алгоритм не сложный легко наверстать набивку кода ручками. При этом немного подумать о функционале, и многопоточности. В перспективе сделаю матрицу на технологии cuda. Но пока-что не могу победить драйвер видеокарты под Linux.И можно сделать матрицу на OpenGL.

Читать дальше......

среда, 24 августа 2011 г.

Факториал в 1 строку.

После реализации сложного и интересного проекта наступает Хандра и кризис идей. Так произошло и после эмулятора SkyNet на питоне(скоро появится статья, о том что это, и вылажу исходники, там много интересных и полезных решений). Сначала решил поcносить все свои системы и поставить заново. Просто от скуки. Сначала поставил Win7. Меня взяла ностальгия и я полтора дня рубился в Rome Total War. Когда надоело, стал лениво листать интересные патерны и трюки на питоне. И вот натыкаюсь на фразу "Реализация факториала через лямбда функцию". Хандру как рукой сняло, глаза загорелись. Захотелось самому додуматься.Браузеры закрыл открыл IDLE Питона и понеслась... Таки сделал, в пол третего ночи, довольный собой, пошел спать. В статье хочу привести пример реализации, и немного подробней рассказать почему оно работает.

К середине статьи я приведу функцию.
Сперва немного теории про лямбда функции. В Вики-учебнике худо расписано, но понять можно.
Лямбда функция эта такая функция которая содержит всего 1 строку(выражение), и в отличии от обыкновенной функции, её легко создать прямо походу выполнения программы.
Используется за частую в аргументах к функциям, при передаче параметров. Если обьяснять на примере то например в вашей программе надо часто использовать подобное выражение( с переменными a,b,c)

sin(ln(a/(b+c*(log(c+b+a))))-sqtr(b+1/c)*tg(a div (c+a)))
И переменные a,b,c постоянно разные, вас задалбывает это всё набирать. И вы делаете следующее:

long_func = lambda a,b,c: sin(ln(a/(b+c*(log(c+b+a))))-sqtr(b+1/c)*tg(a div (c+a))
# И потом используете так
try:
   result = long_func(x,y,z)
except:
   result = -1
   print("Arguments Wrong")
А чтоб сделать рекурсию в лямбде надо вызвать её из самой себя где-то так


recurs = lambda : recurs()
Это сделает бесконечную рекурсию. И так с лямбдой разобрались.
Далее в программе: and, or , not.

Начнём с and.
Смысл функции должен быть ясен логически, не зная о том, что такое дискретная математика. Если мы сообщаем ей 2 правды она скажет "Правда" Если хоть один из аргументов будет ложный, она скажет "Лож". Прошу заметить что притон интерпретирует любое численное значение кроме 0, как правду, а 0 интерпретирует как "Лож". Но в этой функции есть пасхальное яйцо. На котором строится решение выше поставленной задачи. Если мы сообщили ей 2 числовых аргумента(не 0), то она вернёт последний(тот который справа). Если дадим хоть 1 ноль, то она возвращает 0. Но это не всё есть ещё 1 пасхальное яйцо. Которое умно называется Сокращенные вычисления. Насколько мне известно, это присуще почти всем языкам программирования.Смысл вот в чём: при длинном выражении использующем логические функции, вычисление прекращается, как-только встречается хоть 1 переменная решающая итог выражения. Таким образом Что-бы дальше не происходило, на результат это не повлияет.
вот небольшой пример показывающий это:


>>> class F():
 def __init__(self,name,RES):
  self.RES = RES
  self.name = name
 def do(self):
  print self.name
  return self.RES

 
>>> for x in range(10):
 exec("F%s = F('F%s',True)"%(x,x))

 
>>> F4.RES = False
>>> F1.do and F2.do() and F3.do() and F4.do() and F5.do() and F6.do() and F7.do() and F8.do() and F9.do()
F2
F3
F4
False
Для тех кто в не совсем понял что творится: Я создал 10 объектов, при выполнении их метода do() они печатают своё имя, и возвращают True. Кроме 4, его я заставил возвращать False. И так давайте посмотрим, что вышло. А вышло то. что как только 4 объект возвратил False,
все and(ы) перестали выполнятся, потому что в этом нету смысла, всё-рфвно общим результатом будет False.

Теперь про or: or возвратит "Правда" если ХОТЬ 1 элемент правдивый, и возвратит "Лож" если Оба ложны. Пасхальные яйца с and(ом) у or анологичны. Кроме:
Если сообщаем 2 не нуля, то она возвращает нам ПЕРВЫЙ( тот что слева) не ноль, даже если скармливаем ей "Правду " и "не ноль" то она возвратит то что слева. Если пичкаем её двумя неправдами ( будь 0 и False, или False и False, или False и 0, или 0 и 0) Она возвратит нам то что справа. Фокус с Сокращёнными вычислениями, анологичен.
Дальше немножко про функцию not. Что бы её не скормили, она возвратит True, или False. Ну вот пример

>>> not False
True
>>> not True
False
>>> not 0
True
>>> not
Ну и последняя капля ,для тех кто не знает как считается факториал с помошью рекурсии.
Вызывается функция с 2 параметрами, 1 (a) - служебный, собственно он будет результатом. 2(i) - то чиcло факториал которого вы собираетесь получать. В своём теле функция умножает служебный параметр(a) на то число факториал которого вы хотите получить. И полученый результат записывает в (a), после этого функция уменьшает (i) на еденицу, и вызывает себя-же, с новым a и новым i. Так продолжается пока i не станет равным 0, к этому времени в a у нас будет факториал i.
вот код:

def fact_def(a,i):
 if i!=0:
  a=a*i
  i-=1
  return fact_def(a,i)
 else:
  return a
Теперь есть всё, чтоб понять наш пример. Если у вас есть спортивный интерес, лучше не смотрите и постарайтесь на основе вышеизложенного написать своё решение. Я узнавал всё о чём я написал сегодня методом научного тыка, проб, предположений и ошибок. У вас же халява, так что вперёд и с песней.

Ну а для тех кто ленив, то вот :

fact_lambda =lambda a,i: not i-1 and a*i or fact_lambda(a*i,i-1)
Если и сейчас вы недопоняли, то читаем дальше.
Ход 1)Поставлю ка я and. При чём так, что по левую сторону будет i-1, а по правую вызов себя-же с i-1 и a*i. (i-1)and(self(a*i,i-1))
Что это даст? (Я для вас поставлю метку Label1, и бо вернусь к этой строке алгоритма )
Label1: Сначала программа считывает левую сторону и смотрит что она равна True( число ведь) потом правую, а в правой вызывается этаже процедура и повторяется Label1. И так пока левая cторона вдруг не станет 0. Когда это случится вся функция возвратит 0.
К примеру я сказал "Факториал от 1,3" и функция построила рекурсивно для себя вот такую картину (3-1)and(2-1)and(1-1). Когда оно дошло до 1-1. То Рекурсия завершилась, потому что выражение равно False, дальше считать нет смысла.
Ход 2) Пусть будет не and а or, только вместо (i-1) будет not(i-1)   Итого, результат аналогичен. Только функция теперь возвращает не 0 а True, потому что not преобразует 0 в True. Дальше, мы знаем, что функция or когда настигнет правдивый результат( это с левой стороны, для этого надо чтоб i-1 ==0) возвратит нам значение с левой стороны. Значит давайте поместим в левую сторону or, end: ((some1)end(some2))or(some3). При чём этот энд должен возвращать факториал на текущем ходу(a*i) при условии что мы дошли до последнего i  (i=1). То-есть он должен быть гдето таким ( not(i-1) ) and( a*i )  .  Когда i станет 1. not(i-1) возвратит правду, и ( not(i-1) ) and( a*i )  тоже возвратит правду, но не просто правду, а вспомним наши пасхальные яйца, правду из правой её руки. А в её правой руке, находится текущее состояние факториала.
Ход 3) Осталось объеденить. Вспомним что мы сделали в Ходе 1, и в начале Хода 2. Да-да мы планировали, Чтоб вместо True которое возвращает not(i-1) возвращалось значение факториала в данный момент. И вот мы сделали это в конце 2 хода. Вместе это выглядит так.

; (   ( not(i-1) )and( a*i )  )or( self(a*i,i-1) ) 

В так как все логические операторы имеют одинаковый и самый низкий приоритет, скобочки можно убрать, выполнятся они будут последовательно, как раз так, как нам надо. Но со скобочками, мне кажется, нагляднее. Хотя на деле, без скобочек красивее. Ну вот. Разжевал буквально до пюрешки. Вам осталось только сглотнуть.  Спасибо тем у кого хватило терпения дочитать эту статью.
Читать дальше......

воскресенье, 14 августа 2011 г.

PyQt Пару слов о потоках.

Графический интерфеейс очень не любит потоки. Ну это естественно, его основная цель - пеерисовываться, медленно последовательно прорисовать каждый пиксель каждой кнопочки, ему далеко до одновременной перерисоки, Он как библиотекарь к которому приходишь за учебниками в 8 класс, и он по очереди приносит тебе каждый учебник. А когда его терзают одноверменно 4 процессора по поводу перерисовки, он ничего не понимает. И поэтому всех кроме первого посылает В (|) И вываливается с ошибкой. Попробуем организовать что-то типо очереди.

Так-Так. Лабръораторная работа номер N, Работа потоков с графическим интерфейсом.
Сначала я думал так:"а что если сделать действительно очередь". Тоетсь сделать класс Lock примерно таким

class Lock():
def __init__(self):
self.locked = False
def begin(self):
while self.locked:
pass
self.locked = True
def end(self)
self.locked = False
## только потом я обнаружил что
## этот велосипед изобрели до меня 
## в threading.Lock()
сделать обьект такого класса, и обличить изменение интерфейса в бегины,энды. Былобы неплохо.
Так програнывает в консоли в критических секциях, или протсо в выполнении какого-то кода. но не с Qt.Ребята создававшие PyQt видимо подумали что я буду небезопасно изменять их графический интерфейс. Ну вот они и запретили потокам его трогать. Так что трогать интерфейс может только главный поток. Ну и что делать спроситте вы? Можно посылать сигналы главному потоку. Вот это мы и попытаемся сделать. И так упрощённая задача. Есть пользователь User который выглядит гдето так.

class User():
def __init__(self,name):
self.name = name
def event(self):
pass
def do_some(self):
print('user.do some')
T = threading.Thread(None,self.event,None)
T.start()
time.sleep(10)
print(self.name)
Это упрощённый вариант,функциональностью не кишит. Но зато каждый пользователь исключительный. Для нас отличается только именем. Мы видем что в функция метода do_some вызывает event(событие , которое мы потом заменим в процессе написания кода) и потом работает ещё 10 секунд.И печатает имя своё.

Формочка наша, это PlanText и pushButton. большего для тестов не надо( я ленив, не люблю писать формы, даже в Дизайнере)

сlass MainForm(QMainWindow):
def __init__(self):
super(MainForm, self).__init__()
uic.loadUi("test.ui", self)

self.connect(self.pushButton,
SIGNAL("clicked()"),
self.pushButton_Click)

self.engine = Engine(self)


self.connect(self.engine,
SIGNAL('send(int)'), self.receiver)

def pushButton_Click(self):
T = threading.Thread(None,self.engine.userlist[0].do_some,None)
T.start()
print('pushButton_Click')
pass
def receiver(self, value):
self.plainTextEdit.appendPlainText(str(value))
Пожалуй вы в замешательстве, тчо такое engine... engine это класс в котором живёт программа. Если немного посмотреть то Графический интерфейс у нас в MainWindow, Данные( обьекты) с которыми мы будем работать это User. Ну а как мы с ними будем работать, это лежит в engine.
Вот он

class Engine(QObject):
 def __init__(self,form):
  QObject.__init__(self)
  self.form = form
  self.userlist = []
  self.userlist.append(User('Alex'))
  self.userlist[0].event = self.event
 def event(self):
  print('Engine.event')
  for x in range(10):
   self.emit(SIGNAL('send(int)'), x)
   time.sleep(0.1)

Я его наследую от QObject почему? потому что он должен порождать сигналы(emit) а это умеет делать только QObject в конце концов мы ведь с Qt работаем. И сссылку на engine мы помещаем в MainWindow, чтоб можно было вызывать его методы в реакциях на кнопки, и enginу мы сообщаем ссылку на форму, чтоб он мог её изменять.Что у нас есть в engine? У нас есть userlist в котором за жизнь программы будет жить только 1 пользователь Alex. И обратите внимание на строку self.userlist[0].event = self.event Таким образом я тому самому event в Userе присваиваю мой собственный переопределённый event, в котором содержится посылка сигнала на изменение интерфейса.

 def do_some(self):
  print('user.do some')
  T = threading.Thread(None,self.event,None)# да,да вот тут и вызовится
  T.start()
  time.sleep(10)
  print(self.name)

Теперь ещё раз прочитите код в MainWindow Видите, по нажатию кнопки вызывается метод do_some единственного нашего пользователя. В нутри метода do_some вызовется переопроеделённое event в отдельном потоке.
И 10 раз выполнится строка self.emit(SIGNAL('send(int)'), x) что это значит? это значит что класс engine генерирует Сигнал 'send(int)', с параметром x. В это самое время основной поток увидит что сигнал сгенерирован вот это строкой

  self.connect(self.engine,
  SIGNAL('send(int)'), self.receiver)

Что у нас тут? мы приконектили сигнал 'send(int)' от self.engine к функции self.receiver.
Это значит тчо если вдруг self.engine скажет 'send(int)' , то вызовется функция self.receiver с параметром x.

А что у нас в receiverе? а там у нас добавление в PlainText переданного параметра.
И ву-аля, это основной потом, при этом наш Юзер в это время спокойно отрабатывает свои 10 секунд, и никому не надо ждать. Но вы не могли не заметить что do some я вызываю в отдельном потоке, почему? Ведь сигнал я уже с потока посылаю. Потому что если я не вызову отдельный поток, то 10  секунд работы прийдётся выполнять основному потоку, а это значит что в это время он не сможет принимать сигналы и изменять граф. интерфейс,  Сигналы будут строится в очередь,  и только когда 10 секунд работы завершится , сигналы приймутся, и PlanText обновится. А когда я запускаю работу Юзера в потоке, то основной поток свободен для наших нужд. Ну вот. Теперь я и вы, можем делать сложные программы с длинными асинхронными вычислениями и связями, и вовремя отображать на экране всё это, без падений программы, потому , что вся работа лежит на новых потоках. Основной поток занимается только по сути обновлением Окна.




PS: Обратите внимание на передаваемый сигнал с параметром, в сигнале я явно указываю ТИП передаваемого параметра. К примеру если вам нужно передать строку , советую использовать QString. Если надо передать параметр своего типа, то этот тип надо специально зарегестрировать до его передачи с помощью qRegisterMetaType()


Читать дальше......

вторник, 28 июня 2011 г.

Writing Django widgets, или "Никаких учебников, только исходники"


Единственный учебник по программированию который я пока-что прочитал от корки до корки  это "Язык программирования Python" хороший учебник. Многое мне дал. Остальные я использовал как справочники, и читал парочку первых страниц с описанием синтаксиса и основных особенностей.Да-да, это плохое качество, но когда времени нет на 1000 страниц теории, а надо сделать что-то ручками, и работающее, то Документация + http://stackoverflow.com/+ Блоги, и в атаку.
Так было и с Django.
И так, Writing Django widgets.
Информации по этой теме мало, документация хреновая.Поделюсь 2-х дневным опытом.
Widget в переводе с забугорного знать как изобразить.
Что мы будем писать? Виджет календарика.
Я погорячился со словом писать. Ну зачем писать то, что уже давно написано, причём сотни раз,умными трудолюбивыми людьми?
Пусть на другом языке, но написано.
Мы просто прикрутим Скриптик к нашей формочке.
Шаг 1
И так у нас есть простенькая формочка

class ContactForm(forms.Form):
    subject = forms.CharField()
    email = forms.EmailField()
    Date = forms.DateField()
Дабы раскрыть архитектуру действия Вижетов, от календарика мы пока удалимся.

class My_widjet(forms.widgets.TextInput):
    def render(self, name, value, attrs=None):
        return """Простите Блог спот и highlight пытаются интерпритировать HTML Теги""" 
Простите, Блог спот и highlight пытаются интерпритировать HTML Теги.
Поэтому буду давать ссылки: Преведущий код. Да покажите мне такой пример 2 дня назад, я бы не заморачивался столько времени. И нервов бы сохранил. Это, только что, был наш с вами первый виджет. Теперь применим его (когда это возможно я всё-же код буду Пастить сюда)

 class ContactForm(forms.Form):
    subject = forms.CharField()
    email = forms.EmailField()
    Date = forms.DateField(widget = My_widjet)

Ну что, загружайте страничку с вашей формочкой, и "О чудо!" Наш виджет сработал Теперь это вовсе не поле для ввода даты, это ссылка на гугл.
Что от сюда надо вынести?
  •  Виджет целиком и полностью заменяет то к чему его применили. Заменяет он это методом render(он вызывается автоматически), точнее не самим методом а тем что он возвращает. 
Шаг 2
Но согласитесь, целый календарик в строку пихать это совсем по быдлокодерски. Поэтому любимый Django позаботился и дал нам класс Media в Виджете, с помощью него можно по человечески работать с таблицами стилей и яваскриптами . Слава богу, включение скриптов и стилей в Media хорошо продокументировано на официальном сайте. Но есть 1 костыль. Если вы прочти документацию, то увидели, что в последствии в виджете self.media(не люблю когда Питонеры попросту играются с регистром, вместо инициализации интуитивно понятных имён)
будут строки подключения файлов скриптов. Но работать эти строки будут уже в браузере. Я уже был в отчайнии, пока не догадался, что нужно сделать чтоб скрипты подключились. И так в медиа у нас лежит что-то типа 

class Media:
  js = ( 
     "/src/js/unicode-letter.js",
  )
а в render мы прописали что то типа

return "%s some code"%self.media
Таким фигом в браузере у нас
<script type="text/javascript" src="/src/js/unicode-letter.js"></script>
А что по Адресу скриптика? А 404 по адресу скриптика.
И отрубите мне копыта если это есть в официальной документации.
И почему там 404, и что делать? Всё просто. Ваш сайт это не html страница, это Джанго проект, и когда вы запрашиваете его о какой-то  ссылке,  он ищет её в файлике urls.py, и вызывает асоциирующуюся с ней функцию, которая в свою очередь возвращает, запросившему её, данные. Вот такой вот каламбур. Теперь когда нам известна суть проблемы мы может её решить.
Надо в наш фаил привязок добывить такую строку

('^src/([\x20-\x7E]*)/?$',views._catalog),

Для тех кому не понятно советую почитать про регулярные выражения, это очень полезно. Я в кратце поясню при вызове чего- начинающегося на src/... вызывается функция views._catalog с 2 аргументами, 1 - request. А второй это всё что после src/ в виде строки.

Далее создадим функцию _catalog в views


def _catalog(request,path):
 path= ""
 try:
  f = open( os.path.join(os.path.dirname(__file__), 'src/').replace('\\','/')+path,'r')
  path = f.read()
 finally:
  f.close()
 return HttpResponse(path)
Да правильно, она считывает фаил по указаному пути( мы ведь уже не в браузере, и файловая система нам доступна)
И ява скрипт будет работать.
 Что от сюда надо вынести?
  • Привязку пути для ваших скриптов к функции которая их возврашает
Шаг 3  Собственно календарик. Я использовал вот этот чудный календарик JSCal2. Для того чтобы он всплывал и по кнопочке и заполнял поле датой и годом, и временем достаточно сделать так.
Тоесть надо подключить css и Js файлы, и выдать пару строк в ответе. Там около 15 файлов css.Можно было разоборатся, что надо, что не надо, и по  подключать это как должно быть, но я устал, поэтому сделал так. Вот Класс Media для виджета календаря.  Как видете, в нём я создал свою переменную my_css, благодоря этому мне не пришлось прописывать в словарик каждый css файлик.
Ну а теперь целиком весь виджет .
Меня не мало бесит, что приходится подставлять в строку (name,name,name,name) но я не придумал пока как это сделать по дугому. Думал сделать функцию типо этой

def N_times(times,what):
    I=0;
    T=tuple()
    while I<=times:
        I=I+1
        T=T+(what,)
    return T
Но это тоже не очень красиво. Придумаю отпишусь. Ну вот. Календарик есть. Ура. Мы разобрались как работают виджеты и сделали кадендарик который можно подключить в 1 строку к любому field-у.
Читать дальше......

вторник, 24 мая 2011 г.

Макросы это классно

Первое моё знакомство с макросам было случайным. Я обладаю плохим свойством засыпать за чтением учебников. Поэтому учебники я не читаю, и впервые узнал про макросы от преподавателя, который посмотрел что я в сотый раз пишу цикл по 2 переменным и посоветовал мне создать макрос.
Оказалось теперь с помощью
 #define F for(i=0;i<n;i++)
я могу вместо обыкновенного цикла писать просто буковку F. Любопытно также то что Си вполне поддерживает кирилицу в макросах, так что можно по извращатся и набить что-то типа 
#define сделать_10_раз for (i=0; i<10;i++)
Вообще можно весёлый исходник составить.
А теперь макросы в ассемблере, они мне невероятно облегчили жизнь.
Как я задолбался с вечной отладкой и выводом символов порчей регистров, и так далее, но вот ВНЕЗАПНО наткнулся на макрос.
И теперь вместо

push si
push ax
push dx
tabl db '0123456789'
mov si,A
mov ah,2
mov dl,10
int 21h
mov ah,2
mov dl,tabl[si]
int 21h
mov ah,2
mov dl,10
int 21h
pop dx
pop ax
pop si 

Я пишу просто
ToVisual A
где A - то число которое мне надо отобразить.
Классно ещё то что макросам можно сообщать параметры. Да, согласен. Процедуры лучше макросов по занимаемому месту, но по скорости работы макросы выигрывают. Макрос - простая замена текста. Теперь мои программы даже на ассемблере гораздо больше человечны.






















Читать дальше......