Как можно применить произвольные трансформации к изображению с использованием Python?

  • 20 августа 2023 г. 15:46
Ответы на вопрос 3
Для реализации этих шагов можно использовать библиотеку OpenCV вместе с библиотекой NumPy.

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

```python
import cv2
import numpy as np

# Шаг 1: Создание нового изображения
image_path = 'фотография_ноутбука.png'
image = cv2.imread(image_path)

new_image = np.copy(image)

# Шаг 2: Обрезка скриншота экрана
screenshot_path = 'скриншот_экрана.png'
screenshot = cv2.imread(screenshot_path)

# Задайте координаты для обрезки
x, y, w, h = 100, 100, 200, 200
cropped_screenshot = screenshot[y:y+h, x:x+w]

# Шаг 3: Помещение обрезанного скриншота на новое изображение
# Задайте координаты для размещения скриншота
x, y = 300, 300
new_image[y:y+h, x:x+w] = cropped_screenshot

# Шаг 4: Преобразование скриншота (например, изменение размера, поворот и т.д.)
# Здесь приведен пример изменения размера скриншота
resized_screenshot = cv2.resize(cropped_screenshot, (w//2, h//2))

# Шаг 5: Перемещение преобразованного скриншота в заданные координаты
x, y = 500, 200
new_image[y:y+h//2, x:x+w//2] = resized_screenshot

# Шаг 6: Наложение изображения ноутбука поверх пустого изображения с преобразованным скриншотом
# Загрузите изображение ноутбука без экрана
laptop_image_path = 'изображение_ноутбука.png'
laptop_image = cv2.imread(laptop_image_path)

# Задайте координаты для размещения изображения ноутбука
x, y = 0, 0
new_image[y:y+laptop_image.shape[0], x:x+laptop_image.shape[1]] = laptop_image

# Отобразить результат
cv2.imshow('Result', new_image)
cv2.waitKey(0)
cv2.destroyAllWindows()
```

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

Обратите внимание, что в коде используется функция `cv2.resize()` для изменения размера скриншота. Вы также можете использовать другие функции и методы OpenCV для преобразования и наложения изображений, в соответствии с вашими потребностями.
Спасибо за выполнение этой лабораторной работы! 
Код# -*- coding: utf-8 -*-

import sys
import numpy  # pip install numpy
import cv2  # pip install opencv-python

# Функция для загрузки изображения из файла
def loadImg(fname : str) -> numpy.ndarray:
    data = numpy.fromfile(fname, dtype=numpy.uint8)
    img = cv2.imdecode(data, cv2.IMREAD_COLOR)
    if img is None:
        raise IOError("Not an image file")
    return img

# Класс для выбора точек на экране
class Clicker:
    def __init__(self, name: str, image: numpy.ndarray):
        self.wnd = name
        self.image = image
        self.clicks = []
        self.markersize = 5
        self.markercolor = (255,0,255)
        cv2.namedWindow(self.wnd, cv2.WINDOW_AUTOSIZE)
        cv2.setMouseCallback(self.wnd, self._click)
    
    # Рисует точки на изображении и выводит их на экран
    def draw(self):
        copy = self.image.copy()
        color = self.markercolor
        radius = self.markersize
        for x,y in self.clicks:
            cv2.circle(copy, (x,y), radius, color, 1)
            cv2.line(copy, (x-radius,y), (x+radius,y), color, 1)
            cv2.line(copy, (x,y-radius), (x,y+radius), color, 1)
        cv2.imshow(self.wnd, copy)
    
    # Обработка событий мыши
    def _click(self, event, x, y, flags, param):
        if event == cv2.EVENT_LBUTTONDOWN:  # левый клик - поставить точку
            self.clicks.append((x,y))
        elif event == cv2.EVENT_RBUTTONDOWN:  # правый клик - сбросить последнюю точку
            if self.clicks:
                del self.clicks[-1]
        else:
            return
        self.draw()
    
    def close(self):
        cv2.destroyWindow(self.wnd)
    
    def __enter__(self):
        self.draw()
        return self
    
    def __exit__(self, exctype, excvalue, traceback):
        self.close()

try:
    # Загрузка изображений
    image = loadImg('times-square.jpg')  # изображение, внутри которого вписываем другое
    poster = loadImg('lena.png')  # изображение, которое вписываем в первое
except IOError:
    print('Ошибка загрузки файла.')
    sys.exit(1)

# Здесь пользователь выбирает четыре точки на изображении
with Clicker('Select area', image) as clicker:
    while len(clicker.clicks) < 4:  # пока не получили четыре точки - угла
        if cv2.waitKey(100) == 27:
            print('Отменено')
            sys.exit(0)
    pts = numpy.array(clicker.clicks, dtype=numpy.float32)  # выбранные пользователем координаты углов

# Определение углов вставляемого изображения
height, width = poster.shape[:2]
srcpoints = numpy.array([  
    (0,0),
    (width-1, 0),
    (width-1, height-1),
    (0, height-1),
], dtype=numpy.float32)

# Получение матрицы преобразования для перехода от второго изображения к первому
matrix = cv2.getPerspectiveTransform(srcpoints, pts)  

# Применение матрицы преобразования к второму изображению
warped = cv2.warpPerspective(poster, matrix, (image.shape[1], image.shape[0]))

# Создание маски для переноса пикселей с warped на image
mask = numpy.zeros(image.shape, dtype=numpy.uint8) 
cv2.fillPoly(mask, pts.reshape(1, -1, 2).astype(numpy.int32), (1,1,1))
mask.dtype = bool  

# Применение маски для переноса пикселей с warped на image
image[mask] = warped[mask]

# Вывод результата
cv2.imshow('Result', image)
cv2.waitKey()
Мне неясно, с чем именно возникают проблемы, но если говорить в общих чертах о геометрических трансформациях, то есть несколько основных методов. 

Сдвиг - это просто добавление вектора к изначальной позиции объекта. 

Поворот - выполняется с использованием матрицы, умножая её на вектор или картинку. Обратите внимание, что это математическое умножение, а не поэлементное. Для поворота используются матрицы с элементами sin и cos, но нужно уточнить, какая именно матрица применяется.

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

OpenCV поддерживает все эти операции, а также множество других. Вот ссылка на документацию: https://docs.opencv.org/4.x/da/d6e/tutorial_py_geometry_management.html. Вы также упомянули нейронные сети - геометрические трансформации в многомерном пространстве используются и в них.
Похожие вопросы