Описание

Модель машинного обучения, которая классифицирует позу йоги на 4 самых известных асаны, а именно на нисходящую собаку, позу доски, позу дерева, позу богини и позу воина-2 с использованием Mediapipe Blazepose для извлечения признаков.

набор данных

Набор данных представляет собой комбинированный набор данных:

Предварительная обработка изображений

Масштабирование изображений

Изображения сначала изменяются в размере, чтобы уменьшить объем вычислений.

DESIRED_HEIGHT = 480
DESIRED_WIDTH = 480
def resize_2D_array(overall_images):
    new_arr_for_outerdirectory = []
    for i in range(len(overall_images)):
      col = dict[i]
      new_array_for_subdirectory = []
      for j in range(len(overall_images[i])):

        img = overall_images[i][j]
        h, w = img.shape[:2]
        if h < w:
          img = cv2.resize(img, (DESIRED_WIDTH, math.floor(h/(w/DESIRED_WIDTH))))
          print(img.shape)
        
        else:
          img = cv2.resize(img, (math.floor(w/(h/DESIRED_HEIGHT)), DESIRED_HEIGHT))
          print(img.shape)
   
        #appending the image to a new array
        new_array_for_subdirectory.append(img)
      new_arr_for_outerdirectory.append(new_array_for_subdirectory)
    return new_arr_for_outerdirectory

Регулировка яркости

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

#for brightness improvement
def gammaCorrection(src, gamma):
    invGamma = 1 / gamma
 
    table = [((i / 255) ** invGamma) * 255 for i in range(256)]
    table = np.array(table, np.uint8)
 
    return cv2.LUT(src, table)
def isbright(image, dim=10):
    # Resize image to 10x10
    image = cv2.resize(image, (dim, dim))
    # Convert color space to LAB format and extract L channel
    L, A, B = cv2.split(cv2.cvtColor(image, cv2.COLOR_BGR2LAB))
    # Normalize L channel by dividing all pixel values with maximum pixel value
    L = L/np.max(L)
    # Return True if mean is greater than thresh else False
    return np.mean(L)
def changeBrightness(image):
  if (isbright(image) < 0.5):
    gammaImg = gammaCorrection(image, 1)
  elif (isbright(image) > 0.85):
    gammaImg = gammaCorrection(image, 0.75)
  else:
    gammaImg = image
  return gammaImg

def improve_brightness(overall_images):
    new_arr = []
    for i in range(len(overall_images)):
      col = dict[i]
      new_array_1 = []
      for j in range(len(overall_images[i])):
        img = changeBrightness(overall_images[i][j])
        #appending the image to a new array
        new_array_1.append(img)
      new_arr.append(new_array_1)
    return new_arr

Регулировка контрастности

  • Регулирует контраст изображения по его гистограмме.
  • Для повышения контрастности расширяет диапазон интенсивности изображения.
  • Это позволяет областям изображения с более низким контрастом получить более высокий контраст.

# import the neccessasry library
from skimage.exposure import is_low_contrast
def histogram_equalization(img_in):
# segregate color streams
    b,g,r = cv2.split(img_in)
    h_b, bin_b = np.histogram(b.flatten(), 256, [0, 256])
    h_g, bin_g = np.histogram(g.flatten(), 256, [0, 256])
    h_r, bin_r = np.histogram(r.flatten(), 256, [0, 256])
# calculate cdf    
    cdf_b = np.cumsum(h_b)  
    cdf_g = np.cumsum(h_g)
    cdf_r = np.cumsum(h_r)
    
# mask all pixels with value=0 and replace it with mean of the pixel values 
    cdf_m_b = np.ma.masked_equal(cdf_b,0)
    cdf_m_b = (cdf_m_b - cdf_m_b.min())*255/(cdf_m_b.max()-cdf_m_b.min())
    cdf_final_b = np.ma.filled(cdf_m_b,0).astype('uint8')
  
    cdf_m_g = np.ma.masked_equal(cdf_g,0)
    cdf_m_g = (cdf_m_g - cdf_m_g.min())*255/(cdf_m_g.max()-cdf_m_g.min())
    cdf_final_g = np.ma.filled(cdf_m_g,0).astype('uint8')
    cdf_m_r = np.ma.masked_equal(cdf_r,0)
    cdf_m_r = (cdf_m_r - cdf_m_r.min())*255/(cdf_m_r.max()-cdf_m_r.min())
    cdf_final_r = np.ma.filled(cdf_m_r,0).astype('uint8')
    
# merge the images in the three channels
    img_b = cdf_final_b[b]
    img_g = cdf_final_g[g]
    img_r = cdf_final_r[r]
  
    img_out = cv2.merge((img_b, img_g, img_r))
# validation
    equ_b = cv2.equalizeHist(b)
    equ_g = cv2.equalizeHist(g)
    equ_r = cv2.equalizeHist(r)
    equ = cv2.merge((equ_b, equ_g, equ_r))
  
    return img_out
    
def improve_contrast(overall_images):
    new_arr = []
    for i in range(len(overall_images)):
      col = dict[i]
      new_array_1 = []
      for j in range(len(overall_images[i])):
        
        img = overall_images[i][j]
        if(is_low_contrast(img, fraction_threshold=0.05, lower_percentile=1, upper_percentile=99, method='linear')):
          img = histogram_equalization(img)
        #appending the image to a new array
        new_array_1.append(img)
      new_arr.append(new_array_1)
    return new_arr

newarray = improve_contrast(newarray)

Повышение резкости изображений

  • Детектор границ, используемый для вычисления вторых производных изображения.
  • Это определяет, происходит ли изменение значений соседних пикселей от края или непрерывного прогресса. Ядра фильтра Лапласа обычно содержат отрицательные значения в перекрестном шаблоне, центрированном внутри массива. Углы имеют нулевые или положительные значения. Центральное значение может быть как отрицательным, так и положительным.

def sharpenimage(image):
  laplacian_var = cv2.Laplacian(image, cv2.CV_64F).var()
  if laplacian_var < 100:
    kernel = np.array([[0, -1, 0],
                      [-1, 5,-1],
                      [0, -1, 0]])
    sharpened_img = cv2.filter2D(src=image, ddepth=-1, kernel=kernel)
  else:
    sharpened_img = image
  return sharpened_img
def improve_sharpening(overall_images):
    new_arr = []
    for i in range(len(overall_images)):
      col = dict[i]
      new_array_1 = []
      for j in range(len(overall_images[i])):
        img = sharpenimage(overall_images[i][j])
        #appending the image to a new array
        new_array_1.append(img)
      new_arr.append(new_array_1)
    return new_arr

Сегментация тела

  • Функция Media Pipe Segmentation используется для размытия фона изображения.
  • Маска имеет ту же ширину и высоту, что и входное изображение, и содержит значения в диапазоне [0,0, 1,0], где 1,0 и 0,0 обозначают «человеческий» и «фоновый» пиксель соответственно.

Ориентиры позы

  • Поза медийной трубы используется для извлечения 3D-координат 33 суставов из изображения.
  • x и y: координаты ориентира, нормализованные к [0,0, 1,0] по ширине и высоте изображения соответственно.
  • z: представляет глубину ориентира с глубиной в средней точке бедер, являющейся исходной точкой, и чем меньше значение, тем ближе ориентир находится к камере.

Вычисление угла

Ключевые углы в (колене, локте, плече, лодыжке) рассчитываются из точек, извлеченных и помеченных соответствующим названием асаны. Угол в суставе определяется по формуле:

угол = градусы(atan2(y3 — y2, x3 — x2) — math.atan2(y1 — y2, x1 — x2))

def calculateAngle(landmark1, landmark2, landmark3):
 
    x1, y1, _ = landmark1
    x2, y2, _ = landmark2
    x3, y3, _ = landmark3
 
    angle = math.degrees(math.atan2(y3 - y2, x3 - x2) - math.atan2(y1 - y2, x1 - x2))
    
    # Check if the angle is less than zero. 
    if angle< 0:
 
        # Add 360 to the found angle.
        angle += 360
    
    return angle

Результаты модели машинного обучения:

Обучайте и тестируйте алгоритмы машинного обучения (случайный лес, SVC, дерево решений, KNN, Adaboost, RFC) с использованием сгенерированного фрейма данных (csv), чтобы определить, какая модель лучше всего подходит.