Изменение размера изображения без искажений OpenCV
Я использую python 3 и последнюю версию openCV. Я пытаюсь изменить размер изображения с помощью функции изменения размера, но после изменения размера изображение очень искажено. Код:
import cv2
file = "/home/tanmay/Desktop/test_image.png"
img = cv2.imread(file , 0)
print(img.shape)
cv2.imshow('img' , img)
k = cv2.waitKey(0)
if k == 27:
cv2.destroyWindow('img')
resize_img = cv2.resize(img , (28 , 28))
cv2.imshow('img' , resize_img)
x = cv2.waitKey(0)
if x == 27:
cv2.destroyWindow('img')
Исходное изображение 480 x 640 (RGB поэтому я передал 0, чтобы получить его в оттенках серого)
Можно ли каким-либо образом изменить его размер и избежать искажений с помощью OpenCV или любой другой библиотеки? Я намереваюсь сделать рукописный распознаватель цифр, и я обучил свою нейронную сеть, используя данные MNIST, поэтому мне нужно, чтобы изображение было 28x28.
Ответы
Ответ 1
Вы можете попробовать ниже. Функция сохранит частоту исходного изображения.
def image_resize(image, width = None, height = None, inter = cv2.INTER_AREA):
# initialize the dimensions of the image to be resized and
# grab the image size
dim = None
(h, w) = image.shape[:2]
# if both the width and height are None, then return the
# original image
if width is None and height is None:
return image
# check to see if the width is None
if width is None:
# calculate the ratio of the height and construct the
# dimensions
r = height / float(h)
dim = (int(w * r), height)
# otherwise, the height is None
else:
# calculate the ratio of the width and construct the
# dimensions
r = width / float(w)
dim = (width, int(h * r))
# resize the image
resized = cv2.resize(image, dim, interpolation = inter)
# return the resized image
return resized
Вот пример использования.
image = image_resize(image, height = 800)
Надеюсь, что это поможет.
Ответ 2
Если вам нужно изменить разрешение изображения и сохранить соотношение сторон, используйте функцию imutils (см. документацию). как то так:
img = cv2.imread(file , 0)
img = imutils.resize(img, width=1280)
cv2.imshow('image' , img)
надеюсь, это поможет, удачи!
Ответ 3
Ответ, предоставленный @vijay jha, слишком специфичен для конкретного случая. Также включает дополнительное ненужное дополнение. Я предлагаю фиксированный код ниже:
def resize2SquareKeepingAspectRation(img, size, interpolation):
h, w = img.shape[:2]
c = None if len(img.shape) < 3 else img.shape[2]
if h == w: return cv2.resize(img, (size, size), interpolation)
if h > w: dif = h
else: dif = w
x_pos = int((dif - w)/2.)
y_pos = int((dif - h)/2.)
if c is None:
mask = np.zeros((dif, dif), dtype=img.dtype)
mask[y_pos:y_pos+h, x_pos:x_pos+w] = img[:h, :w]
else:
mask = np.zeros((dif, dif, c), dtype=img.dtype)
mask[y_pos:y_pos+h, x_pos:x_pos+w, :] = img[:h, :w, :]
return cv2.resize(mask, (size, size), interpolation)
Код изменяет размер изображения, делая его квадратным и сохраняя аспектный рацион в одно и то же время. Также код подходит для 3-х канальных (цветных) изображений. Пример использования:
resized = resize2SquareKeepingAspectRation(img, size, cv2.INTER_AREA)
Ответ 4
Попробуйте эту простую функцию в Python, которая использует OpenCV. просто передайте изображение и укажите желаемый размер квадрата.
def resize_image(img, size=(28,28)):
h, w = img.shape[:2]
if h == w:
return cv2.resize(img, size, cv2.INTER_AREA)
dif = h if h > w else w
interpolation = cv2.INTER_AREA if dif > (size[0]+size[1])//2 else
cv2.INTER_CUBIC
x_pos = (dif - w)//2
y_pos = (dif - h)//2
if len(img.shape) == 2:
mask = np.zeros((dif, dif), dtype=img.dtype)
mask[y_pos:y_pos+h, x_pos:x_pos+w] = img[:h, :w]
else:
mask = np.zeros((dif, dif, c), dtype=img.dtype)
mask[y_pos:y_pos+h, x_pos:x_pos+w, :] = img[:h, :w, :]
return cv2.resize(mask, size, interpolation)
использование:
squared_image = get_square (изображение, размер = (28,28))
объяснение:
Функция принимает входные данные любого размера и создает пустое изображение квадратной формы с размером изображения по высоте или ширине, в зависимости от того, что больше.
затем он помещает исходное изображение в центр пустого изображения. а затем он изменяет размер этого квадратного изображения до желаемого размера, чтобы сохранить форму исходного изображения.
Надеюсь, что это поможет вам
Ответ 5
У меня есть набор данных для ручных рисунков, и мне нужно создать маленькие квадратные изображения из асимметричных рисунков.
![enter image description here]()
Благодаря @vijay jha я создал квадратные изображения, сохраняя соотношение сторон исходного изображения. Одна из проблем заключалась в том, что чем больше вы уменьшали масштаб, тем больше информации терялось.
От 512x256 до 64x64 будет выглядеть так:
![64x64]()
Я немного изменил исходный код, чтобы плавно уменьшить масштаб изображения.
from skimage.transform import resize, pyramid_reduce
def get_square(image, square_size):
height, width = image.shape
if(height > width):
differ = height
else:
differ = width
differ += 4
# square filler
mask = np.zeros((differ, differ), dtype = "uint8")
x_pos = int((differ - width) / 2)
y_pos = int((differ - height) / 2)
# center image inside the square
mask[y_pos: y_pos + height, x_pos: x_pos + width] = image[0: height, 0: width]
# downscale if needed
if differ / square_size > 1:
mask = pyramid_reduce(mask, differ / square_size)
else:
mask = cv2.resize(mask, (square_size, square_size), interpolation = cv2.INTER_AREA)
return mask
512x256 → 64x64
![enter image description here]()
512x256 → 28x28
![enter image description here]()
Ответ 6
img = cv2.resize(img, (int(img.shape[1]/2), int(img.shape[0]/2)))
изменит размер изображения до половины первоначального размера. Вы можете изменить его для любого другого отношения. Обратите внимание, что первый аргумент, переданный для resize(), - img.shape [1], а не img.shape [0]. Это может противоречить интуиции. Легко упустить этот поворот и получить очень искаженную картину.
Ответ 7
window_height
присваивается значение window_height
посредством которого он вычисляет переменную window_width
при сохранении пропорций изображения. Чтобы предотвратить его искажение.
import cv2
def resize(self,image,window_height = 500):
aspect_ratio = float(image.shape[1])/float(image.shape[0])
window_width = window_height/aspect_ratio
image = cv2.resize(image, (int(window_height),int(window_width)))
return image
img = cv2.imread(img_source) #image location
img_resized = resize(img,window_height = 800)
cv2.imshow("Resized",img_resized)
cv2.waitKey(0)
cv2.destroyAllWindows()
Ответ 8
Не указывайте в соответствие с тем, что задает первоначальный вопрос, но я приземлился здесь, чтобы найти ответ на аналогичный вопрос.
import cv2
def resize_and_letter_box(image, rows, cols):
"""
Letter box (black bars) a color image (think pan & scan movie shown
on widescreen) if not same aspect ratio as specified rows and cols.
:param image: numpy.ndarray((image_rows, image_cols, channels), dtype=numpy.uint8)
:param rows: int rows of letter boxed image returned
:param cols: int cols of letter boxed image returned
:return: numpy.ndarray((rows, cols, channels), dtype=numpy.uint8)
"""
image_rows, image_cols = image.shape[:2]
row_ratio = rows / float(image_rows)
col_ratio = cols / float(image_cols)
ratio = min(row_ratio, col_ratio)
image_resized = cv2.resize(image, dsize=(0, 0), fx=ratio, fy=ratio)
letter_box = np.zeros((int(rows), int(cols), 3))
row_start = int((letter_box.shape[0] - image_resized.shape[0]) / 2)
col_start = int((letter_box.shape[1] - image_resized.shape[1]) / 2)
letter_box[row_start:row_start + image_resized.shape[0], col_start:col_start + image_resized.shape[1]] = image_resized
return letter_box
Ответ 9
Я только что столкнулся с той же проблемой при подготовке набора данных для нейронной сети, и чтобы избежать искажения изображения, я создал функцию, которая изменяет размеры и обрезает изображение минимально, чтобы соответствовать целевому размеру. Сначала он выбирает, следует ли обрезать по оси у или х, сравнивая форматное соотношение входного изображения с целевым форматным соотношением. Затем он изменяет размер входного изображения до ширины или высоты назначения, а затем обрезает по x или y (каждый в зависимости от соотношения сторон).
def crop_and_resize(img, w, h):
im_h, im_w, channels = img.shape
res_aspect_ratio = w/h
input_aspect_ratio = im_w/im_h
if input_aspect_ratio > res_aspect_ratio:
im_w_r = int(input_aspect_ratio*h)
im_h_r = h
img = cv2.resize(img, (im_w_r , im_h_r))
x1 = int((im_w_r - w)/2)
x2 = x1 + w
img = img[:, x1:x2, :]
if input_aspect_ratio < res_aspect_ratio:
im_w_r = w
im_h_r = int(w/input_aspect_ratio)
img = cv2.resize(img, (im_w_r , im_h_r))
y1 = int((im_h_r - h)/2)
y2 = y1 + h
img = img[y1:y2, :, :]
if input_aspect_ratio == res_aspect_ratio:
img = cv2.resize(img, (w, h))
return img