Numpy Resize / Rescale Image


98

Tôi muốn chụp một hình ảnh và thay đổi tỷ lệ của hình ảnh, trong khi đó là một mảng không rõ ràng.

Ví dụ, tôi có hình ảnh chai coca-cola này: chai-1

Điều này chuyển thành một mảng hình dạng nhỏ (528, 203, 3)và tôi muốn thay đổi kích thước đó để nói lên kích thước của hình ảnh thứ hai này: chai-2

Mà có một hình dạng của (140, 54, 3).

Làm cách nào để thay đổi kích thước của hình ảnh thành một hình dạng nhất định trong khi vẫn giữ nguyên hình ảnh gốc? Các câu trả lời khác đề xuất loại bỏ mọi hàng khác hoặc hàng thứ ba, nhưng những gì tôi muốn làm về cơ bản là thu nhỏ hình ảnh theo cách bạn thực hiện thông qua trình chỉnh sửa hình ảnh nhưng bằng mã python. Có thư viện nào để thực hiện việc này trong numpy / SciPy không?


bạn có thể hiển thị mã cho mảng numpy của bạn không?
ShpielMeister


2
@sascha Không được dùng nữa, theo trang bạn đã liên kết.
Paul Panzer

@ShpielMeister Tôi không thể yêu cầu IntelliJ in ra đầy đủ mảng numpy, vì một số lý do khi kết quả đầu ra lớn, nó đặt ... mọi lúc, vì vậy tôi chỉ có thể xem một phần đầu ra của mảng trong bảng điều khiển
Brian Hamill

Câu trả lời:


123

Vâng, bạn có thể cài đặt opencv(đây là một thư viện được sử dụng để xử lý hình ảnh và thị giác máy tính) và sử dụng cv2.resizechức năng này. Và ví dụ sử dụng:

import cv2
import numpy as np

img = cv2.imread('your_image.jpg')
res = cv2.resize(img, dsize=(54, 140), interpolation=cv2.INTER_CUBIC)

imgDo đó, đây là một mảng numpy chứa hình ảnh gốc, trong khi reslà một mảng numpy chứa hình ảnh đã thay đổi kích thước . Một khía cạnh quan trọng là interpolationtham số: có một số cách để thay đổi kích thước hình ảnh. Đặc biệt là vì bạn thu nhỏ hình ảnh và kích thước của hình ảnh gốc không phải là bội số của hình ảnh đã thay đổi kích thước. Các lược đồ nội suy có thể có là:

  • INTER_NEAREST - phép nội suy láng giềng gần nhất
  • INTER_LINEAR - một phép nội suy song tuyến (được sử dụng theo mặc định)
  • INTER_AREA- lấy mẫu lại bằng cách sử dụng quan hệ vùng pixel. Nó có thể là một phương pháp ưa thích để phân rã hình ảnh, vì nó cho kết quả không có moire. Nhưng khi phóng to hình ảnh, nó cũng tương tự như INTER_NEARESTphương pháp.
  • INTER_CUBIC - phép nội suy lưỡng cực trên vùng lân cận 4x4 pixel
  • INTER_LANCZOS4 - phép nội suy Lanczos trên vùng lân cận 8x8 pixel

Giống như với hầu hết các tùy chọn, không có tùy chọn "tốt nhất" theo nghĩa là đối với mọi lược đồ thay đổi kích thước, có những tình huống trong đó một chiến lược có thể được ưu tiên hơn một chiến lược khác.


5
Tôi vừa thử mã này và nó hoạt động! Chỉ cần một sự thay đổi là dsizenên dsize=(54, 140)như phải mất x sau đó y, trong đó như là một mảng show NumPy hình dạng như y thì x (y là số hàng và x là số cột)
Brian Hamill

6
Tôi cố gắng tránh cv2, nó hoán đổi kích thước và tải ở định dạng kênh BGR. Tôi thích skimage.io.imread('image.jpg')skimage.transform.resize(img). scikit-image.org/docs/dev/install.html
Eduardo Pignatelli

1
@EduardoPignatelli Tôi tránh skimage.transform.resize vì bạn không có quyền kiểm soát thuật toán nội suy mà nó sử dụng. Nhưng, điều đó có thể không quan trọng, tùy thuộc vào trường hợp sử dụng của mọi người.
Decker

2
@Decker skimage.transform.resize cung cấp một số điều khiển thông qua tham số 'order'. order = 0 là láng giềng gần nhất, 1 = song tuyến tính, 2 = nhị thức, 3 = nhị phương, v.v. Tuy nhiên, không có trung bình diện tích hoặc phép nội suy lanczos.
Tapio

1
@TapioFriberg à vâng, tôi đã sửa lại; Tôi thấy các thuật toán được xác định trong tài liệu cho tham số 'order' của skimage.transform.warp. Tại một số thời điểm, có thể hữu ích nếu cập nhật tài liệu để bao gồm các tham chiếu cho các loại, ví dụ: "Bi-tứ phân vị" không được xác định ở bất kỳ nơi nào khác trong tài liệu, (kể từ ngày 10 tháng 12 năm 2019) - một lớp lót có thể có lợi cho người dùng trong tương lai.
Decker

67

Mặc dù có thể chỉ sử dụng numpy để làm điều này, nhưng hoạt động này không được tích hợp sẵn. Điều đó nói rằng, bạn có thể sử dụng scikit-image(được xây dựng trên numpy) để thực hiện loại thao tác hình ảnh này.

Tài liệu thay đổi tỷ lệ Scikit-Image có ở đây .

Ví dụ: bạn có thể làm như sau với hình ảnh của mình:

from skimage.transform import resize
bottle_resized = resize(bottle, (140, 54))

Điều này sẽ giải quyết những việc như nội suy, khử răng cưa, v.v. cho bạn.


2
Cảm ơn bạn! Câu trả lời này cũng hoạt động! Mặc dù tôi nhận được một số vấn đề với anti_aliasingcờ, có vẻ như nó đã bị xóa khỏi phiên bản mới nhất của 0.13.1
Brian Hamill

8
Hình ảnh lợi nhuận này như phao ndarray ngay cả khi hình ảnh ban đầu của bạn là uint8
sziraqui

3
Đây là một kỹ thuật hay vì nó hoạt động với bất kỳ số lượng kênh nào. Tôi đã thử điều này với dữ liệu rgb kết hợp với dữ liệu đám mây điểm độ sâu và nó bảo toàn mối quan hệ như tôi muốn.
Darth Egrerious

@DarthEgrerious, jakevdp -> nó làm cho dữ liệu nhiễu ngẫu nhiên của tôi thành một màu duy nhất khi tôi thay đổi kích thước mảng (137,236,3) thành (64,64) như phương pháp bạn đã mô tả. Điều này có bình thường không vì có vẻ như nó đã bị mất tất cả thông tin?
Deshwal

1
Không nên (64,64,3)
Darth Egrerious

14

Đối với những người đến đây từ Google đang tìm kiếm một cách nhanh chóng để giảm mẫu hình ảnh trong numpycác mảng để sử dụng trong các ứng dụng Máy học, đây là một phương pháp siêu nhanh (được điều chỉnh từ đây ). Phương pháp này chỉ hoạt động khi kích thước đầu vào là bội số của kích thước đầu ra.

Các ví dụ sau giảm mẫu từ 128x128 xuống 64x64 (điều này có thể dễ dàng thay đổi).

Các kênh đặt hàng gần đây nhất

# large image is shape (128, 128, 3)
# small image is shape (64, 64, 3)
input_size = 128
output_size = 64
bin_size = input_size // output_size
small_image = large_image.reshape((output_size, bin_size, 
                                   output_size, bin_size, 3)).max(3).max(1)

Các kênh đặt hàng đầu tiên

# large image is shape (3, 128, 128)
# small image is shape (3, 64, 64)
input_size = 128
output_size = 64
bin_size = input_size // output_size
small_image = large_image.reshape((3, output_size, bin_size, 
                                      output_size, bin_size)).max(4).max(2)

Đối với hình ảnh màu xám chỉ cần thay đổi 3một 1như thế này:

Các kênh đặt hàng đầu tiên

# large image is shape (1, 128, 128)
# small image is shape (1, 64, 64)
input_size = 128
output_size = 64
bin_size = input_size // output_size
small_image = large_image.reshape((1, output_size, bin_size,
                                      output_size, bin_size)).max(4).max(2)

Phương pháp này sử dụng tương đương với tổng hợp tối đa. Đó là cách nhanh nhất để làm điều này mà tôi đã tìm thấy.


4
big_image [:, :: 2, :: 2] trả về hình ảnh có độ phân giải giảm đi một nửa.
L. Kärkkäinen

1
@ LasseKärkkäinen nhưng nó không giảm bớt mẫu, nó chỉ chọn mọi pixel khác. Sự khác biệt là hàm cuối cùng 'max' có thể được thay đổi để chọn hoặc tính toán pixel theo những cách tốt hơn một chút (ví dụ: sử dụng 'min' hoặc 'mean'). Phương pháp của bạn hữu ích (và nhanh hơn), nếu điều đó không quan trọng.
Waylon Flinn

@ L.Kärkkäinen điều này ngược lại với độ phân giải kép là gì?
rayzinnz

2
@rayzinnznp.repeat(np.repeat(a, 2, axis=0), 2, axis=1)
L. Kärkkäinen

11

Nếu bất kỳ ai đến đây tìm kiếm một phương pháp đơn giản để thay đổi kích thước / thay đổi kích thước hình ảnh bằng Python mà không cần sử dụng các thư viện bổ sung, thì đây là một hàm thay đổi kích thước hình ảnh rất đơn giản:

#simple image scaling to (nR x nC) size
def scale(im, nR, nC):
  nR0 = len(im)     # source number of rows 
  nC0 = len(im[0])  # source number of columns 
  return [[ im[int(nR0 * r / nR)][int(nC0 * c / nC)]  
             for c in range(nC)] for r in range(nR)]

Cách sử dụng ví dụ: thay đổi kích thước hình ảnh (30 x 30) thành (100 x 200):

import matplotlib.pyplot as plt

def sqr(x):
  return x*x

def f(r, c, nR, nC):
  return 1.0 if sqr(c - nC/2) + sqr(r - nR/2) < sqr(nC/4) else 0.0

# a red circle on a canvas of size (nR x nC)
def circ(nR, nC):
  return [[ [f(r, c, nR, nC), 0, 0] 
             for c in range(nC)] for r in range(nR)]

plt.imshow(scale(circ(30, 30), 100, 200))

Đầu ra: hình ảnh được chia tỷ lệ

Điều này hoạt động để thu nhỏ / chia tỷ lệ hình ảnh và hoạt động tốt với các mảng có nhiều nếp gấp.


4

imresize()Phương pháp của SciPy là một phương pháp thay đổi kích thước khác, nhưng nó sẽ bị xóa bắt đầu với SciPy v 1.3.0. SciPy đề cập đến phương pháp thay đổi kích thước hình ảnh PIL :Image.resize(size, resample=0)

kích thước - Kích thước được yêu cầu tính bằng pixel, dưới dạng 2 bộ: (chiều rộng, chiều cao).
resample - Bộ lọc lấy mẫu lại tùy chọn. Đây có thể là một trong PIL.Image.NEAREST (sử dụng hàng xóm gần nhất), PIL.Image.BILINEAR (nội suy tuyến tính), PIL.Image.BICUBIC (nội suy hình khối) hoặc PIL.Image.LANCZOS (một bộ lọc giảm mẫu chất lượng cao ). Nếu bị bỏ qua hoặc nếu hình ảnh có chế độ “1” hoặc “P”, nó sẽ được đặt PIL.Image.NEAREST.

Liên kết tại đây: https://pillow.readthedocs.io/en/3.1.x/reference/Image.html#PIL.Image.Image.resize


3
Thật không may, imresize () bị phản đối, nó sẽ được loại bỏ trong scipy 1.3.0
MiniQuark

1

Có thư viện nào để thực hiện việc này trong numpy / SciPy không

Chắc chắn rồi. Bạn có thể làm điều này mà không cần OpenCV, scikit-image hoặc PIL.

Thay đổi kích thước hình ảnh về cơ bản là ánh xạ tọa độ của mỗi pixel từ hình ảnh gốc đến vị trí đã thay đổi kích thước của nó.

Vì tọa độ của hình ảnh phải là số nguyên (hãy nghĩ về nó như một ma trận), nếu tọa độ được ánh xạ có giá trị thập phân, bạn nên nội suy giá trị pixel để xấp xỉ nó với vị trí số nguyên (ví dụ: lấy pixel gần nhất đến vị trí đó đã biết như nội suy láng giềng gần nhất ).

Tất cả những gì bạn cần là một hàm thực hiện nội suy này cho bạn. SciPy có interpolate.interp2d.

Bạn có thể sử dụng nó để thay đổi kích thước hình ảnh trong mảng numpy, chẳng hạn arrnhư sau:

W, H = arr.shape[:2]
new_W, new_H = (600,300)
xrange = lambda x: np.linspace(0, 1, x)

f = interp2d(xrange(W), xrange(H), arr, kind="linear")
new_arr = f(xrange(new_W), xrange(new_H))

Tất nhiên, nếu hình ảnh của bạn là RGB, bạn phải thực hiện nội suy cho từng kênh.

Nếu bạn muốn hiểu thêm, tôi khuyên bạn nên xem Thay đổi kích thước hình ảnh - Computerphile .


Có thể không hoạt động dựa trên câu trả lời này: stackoverflow.com/questions/37872171/…
random_dsp_guy

0
import cv2
import numpy as np

image_read = cv2.imread('filename.jpg',0) 
original_image = np.asarray(image_read)
width , height = 452,452
resize_image = np.zeros(shape=(width,height))

for W in range(width):
    for H in range(height):
        new_width = int( W * original_image.shape[0] / width )
        new_height = int( H * original_image.shape[1] / height )
        resize_image[W][H] = original_image[new_width][new_height]

print("Resized image size : " , resize_image.shape)

cv2.imshow(resize_image)
cv2.waitKey(0)

4
Chào mừng bạn đến với StackOverflow. Thật tuyệt khi bạn muốn giúp đỡ người khác bằng cách trả lời câu hỏi của họ. Tuy nhiên, tôi không thấy câu trả lời của bạn thêm giá trị như thế nào so với câu trả lời hiện tại đã sử dụng cv2và sử dụng một hàm thay đổi kích thước thích hợp thay vì thực hiện lại một hàm thay đổi kích thước "tối ưu phụ" kém hơn so với phép nội suy hàng xóm gần nhất.
NOhs
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.