Архив за месяц: Май 2014

Как определить HSV цвет в OpenCV (python)

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

cv2.inRange(src, lowerb, upperb[, dst])

позволяет выделить маску области. Однако резко встает вопрос корректного определения верхней и нижней границы (lowerb и upperb). А в этом как раз и прелесть и сложность пространства HSV. Кодировка цвета в модели HSV расшифровывается так: H — цветовой тон, S — насыщенность, V — яркость. Поэтому для выделения по цвету, достаточно указать диапазон H, а насыщенность и яркость будет сильно варьироваться (из-за разной освещенности, углов скоса объекта и.т.д.) На практике обычно делают примерно так: если H соcтавляющая 80 (зеленый цвет), берут нижнюю границу H=80-10 [70, 50, 50], а верхнюю H=80+10 [90,255,255]. Кажется что вот, все просто, посмотрим HSV цвет в фотошопе или пейнте и установим нужную границу… Но, в отличии от цветовой модели RGB, диапазон значений H в разных программах может задаваться по разному и его необходимо пересчитывать. Чтобы облегчить и на лету определять HSV цвет в OpenCV написал следующий небольшой скрипт:

import cv2
import cv2.cv as cv

cap = cv2.VideoCapture(0)

#set camera width and height
CAM_WIDTH = 640
CAM_HEIGHT = 480
cap.set(cv.CV_CAP_PROP_FRAME_WIDTH, CAM_WIDTH)
cap.set(cv.CV_CAP_PROP_FRAME_HEIGHT, CAM_HEIGHT)

selected_color = None
image_origin = None


def onmouse(event, x, y, flags, param):
    global image_origin, selected_color
    if flags & cv2.EVENT_FLAG_LBUTTON:
        #taking squire cur 4x4 and scale it to 1x1
        cut = image_origin[y-1:y+2, x-1:x+2]
        cut = cv2.pyrDown(cut)
        cut = cv2.pyrDown(cut)

        selected_color = (int(cut[0][0][0]), int(cut[0][0][1]), int(cut[0][0][2]))
        #conveting to HSV and printing result
        selected_color_HSV = cv2.cvtColor(cut, cv2.COLOR_BGR2HSV)
        print(selected_color_HSV)

while(1):

    # Take each frame
    _, frame = cap.read()
    image_origin = frame.copy()


    #drawing selected colors
    if selected_color is not None:
        cv2.circle(frame, (CAM_WIDTH-20,20), 20, selected_color, -1)

    #show image and set callback
    cv2.imshow('img', frame)
    cv2.setMouseCallback('img', onmouse)

    k = cv2.waitKey(5) & 0xFF
    if k == 27:
        break

cv2.destroyAllWindows()

В данном пример изображение берется из видео-потока. Идея состоит в том, что после клика по видео изображению, выделяется квадрат 4 на 4, этот квадрат уменьшаем до размера 1 на 1 (усредняем значения цвета) и с помощью функции cv2.cvtColor(img, cv2.COLOR_BGR2HSV) переводим изображение в режим HSV.

Надеюсь этот скрипт поможет вам для работы в приложениях с OpenCV.

Как определить одушевленность существительного на Python?

Предположим, что нам на вход подается произвольное слово и необходимо узнать является ли оно одушевленным или нет. Причем одушевленность надо проверить только для имен существительных. Один из простых способов узнать одушевленность это:

  1. Проверить, является ли слово существительным
  2. поставить слово в форму винительного падежа множественного числа
  3. поставить слово в форму родительного падежа множественного числа
  4. сравнить 2 и 3 и если формы совпадут, то слово будет одушевленным, в противном случае — неодушевленным

Согласно данному алгоритмы напишем код на python с использованием pymorphy2:

# -*- coding: utf-8 -*-
import pymorphy2

def isAnimateNoun(word):
    morph = pymorphy2.MorphAnalyzer()
    parsed = morph.parse( word )

    #if not parsed, return False
    if len(parsed) == 0:
        return False

    #let's check if word is Noun.
    #if we have multiple variations, let's take first
    noun_word = None
    for variant in parsed:
        if {'NOUN'} in variant.tag:
            noun_word = variant
            break

    if noun_word is None:
        return False

    #checking forms
    #множественное число родительного и винительного падежа
    gent_case = noun_word.inflect({'plur', 'gent'})
    accs_case = noun_word.inflect({'plur', 'accs'})
    if gent_case is None or accs_case is None:
        return False

    if gent_case.word == accs_case.word:
        print(gent_case.word)
        return True
    else:
        return False

print(isAnimateNoun(u'динозавр'))

Данный способ весьма прост, но его точность гарантировать не буду. Т.к. в случае мужского рода частенько проверяют формы слова 2 и 3 и для единственного числа. Однако, разработчики pymorphy2 уже озадачились данной проблемой и оказывается достаточно написать следующий код:

# -*- coding: utf-8 -*-
import pymorphy2

def isAnimateNoun2(word):
    morph = pymorphy2.MorphAnalyzer()
    parsed = morph.parse( word )

    #if not parsed, return False
    if len(parsed) == 0:
        return False

    #let's check if word is Noun.
    #if we have multiple variations, let's take first
    for variant in parsed:
        if {'NOUN'} in variant.tag:
            if variant.tag.animacy is not None and variant.tag.animacy == "anim": #inan, anim
                return True

    return False

print(isAnimateNoun2(u'динозавр'))

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

Национальности мира в мужском роде на pymorphy2

Получить файл с национальностями мира не так то уж и сложно, достаточно зайти на ту же википедию, скопировать искомую таблицу и немного подредактировать. Что собственно я и сделал, получился следующий файл ( скачать национальности мира txt ). Однако все источники, которые удалось найти, предлагают национальности только во множественном числе, т.е. не «китаец» а «китайцы», не «японец», а «японцы».  А как Вы могли понять, для моей задачи требуется выделять национальность в мужском роде единственного числа. Немного поразмыслив, решил воспользоваться морфологическим анализатором pymorphy2, который написан на Python и позволяет ставить слово в нужную форму. Пишем следующий скрипт:

# -*- coding: utf-8 -*-
import pymorphy2

morph = pymorphy2.MorphAnalyzer()

generated_nationalities = [] #

file = open('all_nationality.txt', 'r')
for line in file.readlines():
    line = line.strip() #deleting unnecessary spaces
    if ' ' in line: continue #not processing several words
    parsed = morph.parse( line.decode('utf-8') )
    if len(parsed) == 0: continue #if pymorphy converted
    parsed = parsed[0]
    res = parsed.inflect({'sing', 'nomn'})
    if res is None: continue #continue if can not generate
    print(res.word)

    generated_nationalities.append( line + ', ' + res.word.encode('utf-8') )
file.close()

#writing to file
file_generated = open('generated_nationalities.txt', 'w')
file_generated.write( "\n".join(generated_nationalities) )
file_generated.close()

Немного поясню код:

  1. Сначала подключаем библиотеку pymorphy2 и инициализируем морфологический анализатор.
  2. Для каждой строки, содержащую национальность, убираем ненужные пробелы и знак переноса строки
  3. Если национальность состоит из нескольких слов, то пропускаем (возможно в следующий раз будем изменять словосочетания вроде «суринамцы индийского происхождения» но для текущей задачи это избыточно )
  4. Генерируем национальность в единственном числе и добавляем в список
  5. На последнем шаге происходит запись в файл полученного списка

В результате исполнения данной программы получился следующий файл - национальности в мужском роде txt Хорошо бы было ещё получить национальности и в женском роде, но pymorphy этого делать пока не позволяет

Привет, мир!

Добро пожаловать в WordPress. Это ваша первая запись. Отредактируйте или удалите её, затем пишите!