Убираем радиальное искажение с фото и видео при помощи библиотеки openCV и языка python

МЕНЮ


Искусственный интеллект. Новости
Поиск

ТЕМЫ


Внедрение ИИНовости ИИРобототехника, БПЛАТрансгуманизмЛингвистика, обработка текстаБиология, теория эволюцииВиртулаьная и дополненная реальностьЖелезоКиберугрозыНаучный мирИТ индустрияРазработка ПОТеория информации

RSS


RSS новости

Авторизация



Новостная лента форума ailab.ru

В данной статье будет рассказываться о применении библиотеки машинного зрения (openCV) для удаления эффекта радиального искажения (дисторсии) с фото и видео. Данный эффект также известен как эффект рыбьего глаза (fisheye) или distortion. Решение написать данную статью было принято после нескольких дней поиска информации в интернете. Не смотря на то, что есть гайды на английском языке, они не объясняют как правильно установить openCV, чтобы все работало. В статье присутствует готовый код.

Сразу привожу фото итогового результата. Слева оригинальное фото, справа — обработанное:

before after

Сборка и установка openCV

Первое, что нужно сделать, это грамотно установить библиотеку openCV. Для этого скачиваем из официального репозитория два проекта — openCV и opencv_contrib.

git clone https://github.com/opencv/opencv.git git clone https://github.com/opencv/opencv_contrib.git

Пока загружается openCV, устанавливаем видеокодек ffmpeg:

sudo apt-get install ffmpeg

Заходим в папку openCV, создаем подпапку buid и заходим в нее. Вся работа по сборке и установке библиотеки openCV будет производиться из этой директории.

cd opencv mkdir build cd build/

Для сборки библиотеки выполняем следующие команды:

cmake .. -DOPENCV_EXTRA_MODULES_PATH=/путь к папке opencv_contrib/modules/ /путь к папке opencv/ make -j5 sudo make install

У меня сборка заняла около полутора часов, установка — несколько минут. Обратите внимание: если у вас возникла ошибка при сборке(выполнение команды cmake), для нового запуска необходимо удалить файл CMakeCache.txt. После установки можем проверить все ли правильно получилось. Для этого можно вызвать рабочую среду python и импортировать библиотеку openCV. Если никаких ошибок не произошло, то вы все сделали правильно. Вторая строчка покажет, какая версия у вас установлена. На момент написания статьи я пользовался 3 версией библиотеки.

import cv2 print ("OpenCV version : {0}".format(cv2.__version__))

Калибровка камеры

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

Определение поправочных коэффициентов

from __future__ import print_function import numpy as np import cv2 from common import splitfn import os  if __name__ == '__main__':     import sys     import getopt     from glob import glob      args, img_mask = getopt.getopt(sys.argv[1:], '', ['debug=', 'square_size='])     args = dict(args)     args.setdefault('--debug', '/рабочая директория/')     args.setdefault('--square_size', 1.0)     if not img_mask:         img_mask = '/папка с изображениями/*.png'     else:         img_mask = img_mask[0]      img_names = glob(img_mask)     debug_dir = args.get('--debug')     if not os.path.isdir(debug_dir):         os.mkdir(debug_dir)     square_size = float(args.get('--square_size'))      pattern_size = (9, 6)     pattern_points = np.zeros((np.prod(pattern_size), 3), np.float32)     pattern_points[:, :2] = np.indices(pattern_size).T.reshape(-1, 2)     pattern_points *= square_size      obj_points = []     img_points = []     h, w = 0, 0     img_names_undistort = []     for fn in img_names:         print('processing %s... ' % fn, end='')         img = cv2.imread(fn, 0)         if img is None:             print("Failed to load", fn)             continue          h, w = img.shape[:2]         found, corners = cv2.findChessboardCorners(img, pattern_size)         if found:             term = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_COUNT, 30, 0.1)             cv2.cornerSubPix(img, corners, (5, 5), (-1, -1), term)          if not found:             print('chessboard not found')             continue          img_points.append(corners.reshape(-1, 2))         obj_points.append(pattern_points)          print('ok')      rms, camera_matrix, dist_coefs, rvecs, tvecs = cv2.calibrateCamera(obj_points, img_points, (w, h), None, None)      print(" RMS:", rms)     print("camera matrix: ", camera_matrix)     print("distortion coefficients: ", dist_coefs.ravel())      cv2.destroyAllWindows()


В результате выполнения данного скрипта в консоли появится сообщение об обработанных фото и отобразятся два важных параметра — camera matrix и distortion coefficients. Это и есть те калибровочные коэффициенты, которые нам нужны.

coef

Обработка фото и видео

Для обработки фото и/или видио необходимо выполнить скрипты, приведенные ниже. В скриптах нужно указать свои калибровочные параметры и рабочие папки.

Скрипт для обработки фото

from __future__ import print_function import numpy as np import cv2 import glob from matplotlib import pyplot as plt from common import splitfn import os  img_names_undistort = [img for img in glob.glob("/путь до папки с фотографиями/*.png")] new_path = "/путь для сохранения обработанных изображений/"  camera_matrix = np.array([[1.26125746e+03, 0.00000000e+00, 9.40592038e+02],                           [0.00000000e+00, 1.21705719e+03, 5.96848905e+02],                           [0.00000000e+00, 0.00000000e+00, 1.00000000e+00]]); dist_coefs = np.array([-0.49181345,  0.25848255, -0.01067125, -0.00127517, -0.01900726]);  i = 0  #for img_found in img_names_undistort: while i < len(img_names_undistort):         img = cv2.imread(img_names_undistort[i])     img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)          h,  w = img.shape[:2]         newcameramtx, roi = cv2.getOptimalNewCameraMatrix(camera_matrix, dist_coefs, (w, h), 1, (w, h))          dst = cv2.undistort(img, camera_matrix, dist_coefs, None, newcameramtx)      dst = cv2.cvtColor(dst, cv2.COLOR_BGR2RGB)          # crop and save the image         x, y, w, h = roi         dst = dst[y:y+h-50, x+70:x+w-20]      name = img_names_undistort[i].split("/")     name = name[6].split(".")     name = name[0]     full_name = new_path + name + '.jpg'          #outfile = img_names_undistort + '_undistorte.png'         print('Undistorted image written to: %s' % full_name)         cv2.imwrite(full_name, dst)     i = i + 1


Скрипт для обработки видео

from __future__ import print_function import numpy as np import cv2 import glob from matplotlib import pyplot as plt from common import splitfn import os  FILENAME_IN = "videoin.mp4" FILENAME_OUT = "videoout.mp4" CODEC = 'mp4v'   camera_matrix = np.array([[1.26125746e+03, 0.00000000e+00, 9.40592038e+02],                           [0.00000000e+00, 1.21705719e+03, 5.96848905e+02],                           [0.00000000e+00, 0.00000000e+00, 1.00000000e+00]]); dist_coefs = np.array([-3.18345478e+01, 7.26874187e+02, -1.20480816e-01, 9.43789095e-02, 5.28916586e-01]);  print ("OpenCV version : {0}".format(cv2.__version__)) print((cv2.__version__).split('.')) # Load video video = cv2.VideoCapture(FILENAME_IN)  fourcc = cv2.VideoWriter_fourcc(*list(CODEC))  fps = video.get(cv2.CAP_PROP_FPS)  frame_count = video.get(cv2.CAP_PROP_FRAME_COUNT)  size = (int(video.get(cv2.CAP_PROP_FRAME_WIDTH)),         int(video.get(cv2.CAP_PROP_FRAME_HEIGHT))) sizew = (1676, 846) writer = cv2.VideoWriter(FILENAME_OUT, fourcc, 25, sizew)  newcameramtx, roi = cv2.getOptimalNewCameraMatrix(camera_matrix, dist_coefs, (size[0], size[1]), 1, (size[0], size[1])) x, y, w, h = roi M = cv2.getRotationMatrix2D((size[0]/2,size[1]/2),5,1)  while video.grab() is True:     print("On frame %i of %i."%(video.get(cv2.CAP_PROP_POS_FRAMES), frame_count))      frame = video.retrieve()[1]     frame = cv2.undistort(frame, camera_matrix, dist_coefs, None, newcameramtx)     frame = frame[y:y+h-50, x+70:x+w-20]      writer.write(frame) video.release() writer.release()


Источник: habrahabr.ru