Numpy Resize / Rescale Image


98

ฉันต้องการถ่ายภาพและเปลี่ยนมาตราส่วนของภาพในขณะที่มันเป็นอาร์เรย์ตัวเลข

ตัวอย่างเช่นฉันมีรูปขวดโคคาโคล่า: bottle-1

ซึ่งแปลเป็นอาร์เรย์ของรูปร่างที่เป็นตัวเลข(528, 203, 3)และฉันต้องการปรับขนาดเพื่อบอกขนาดของภาพที่สองนี้: bottle-2

ซึ่งมีรูปร่างเป็น(140, 54, 3).

ฉันจะเปลี่ยนขนาดของรูปภาพเป็นรูปร่างที่แน่นอนได้อย่างไรในขณะที่ยังคงรักษาภาพต้นฉบับไว้ คำตอบอื่น ๆ แนะนำให้แยกแถวอื่น ๆ หรือแถวที่สามออก แต่สิ่งที่ฉันต้องการทำโดยพื้นฐานแล้วคือย่อขนาดรูปภาพตามที่คุณต้องการผ่านโปรแกรมแก้ไขภาพ แต่อยู่ในรหัส python มีไลบรารีใดบ้างที่ทำใน numpy / SciPy


คุณสามารถแสดงโค้ดสำหรับอาร์เรย์ numpy ของคุณได้ไหม
ShpielMeister


2
@sascha เลิกใช้งานตามหน้าที่คุณเชื่อมโยง
Paul Panzer

@ShpielMeister ฉันไม่สามารถให้ IntelliJ พิมพ์อาร์เรย์ numpy ได้อย่างสมบูรณ์ด้วยเหตุผลบางประการเมื่อเอาต์พุตมีขนาดใหญ่ทำให้ ... ตลอดเวลาดังนั้นฉันจึงเห็นเพียงบางส่วนของเอาต์พุตอาร์เรย์ในคอนโซล
Brian Hamill

คำตอบ:


123

ใช่คุณสามารถติดตั้งopencv(นี่คือไลบรารีที่ใช้สำหรับการประมวลผลภาพและการมองเห็นของคอมพิวเตอร์) และใช้cv2.resizeฟังก์ชันนี้ และสำหรับการใช้งานเช่น:

import cv2
import numpy as np

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

นี่imgคืออาร์เรย์ numpy ที่มีรูปภาพต้นฉบับในขณะที่resอาร์เรย์ numpy ที่มีรูปภาพที่ปรับขนาดแล้ว สิ่งสำคัญคือinterpolationพารามิเตอร์: มีหลายวิธีในการปรับขนาดรูปภาพ โดยเฉพาะอย่างยิ่งเมื่อคุณลดขนาดรูปภาพลงและขนาดของรูปภาพต้นฉบับไม่ได้เป็นหลายขนาดของรูปภาพที่ปรับขนาด แผนผังการแก้ไขที่เป็นไปได้ ได้แก่ :

  • INTER_NEAREST - การแก้ไขเพื่อนบ้านที่ใกล้ที่สุด
  • INTER_LINEAR - การแก้ไขทวิภาคี (ใช้โดยค่าเริ่มต้น)
  • INTER_AREA- การสุ่มตัวอย่างใหม่โดยใช้ความสัมพันธ์ของพื้นที่พิกเซล อาจเป็นวิธีที่ต้องการสำหรับการลดขนาดรูปภาพเนื่องจากให้ผลลัพธ์ที่ไม่มัวร์ แต่เมื่อซูมภาพแล้วก็คล้ายกับ INTER_NEARESTวิธีการ
  • INTER_CUBIC - การแก้ไขแบบ bicubic ในย่านพิกเซล 4x4
  • INTER_LANCZOS4 - การแก้ไข Lanczos ในพื้นที่ใกล้เคียง 8x8 พิกเซล

เช่นเดียวกับตัวเลือกส่วนใหญ่ไม่มีตัวเลือกที่ "ดีที่สุด" ในแง่ที่ว่าสำหรับสคีมาการปรับขนาดทุกครั้งมีสถานการณ์ที่กลยุทธ์หนึ่งสามารถเลือกใช้มากกว่าอีกกลยุทธ์หนึ่งได้


5
ฉันเพิ่งลองใช้รหัสนี้และใช้งานได้! การเปลี่ยนแปลงเพียงอย่างเดียวคือdsizeควรเป็นไปdsize=(54, 140)ตามที่ใช้ x แล้ว y โดยที่อาร์เรย์ numpy แสดงรูปร่างเป็น y แล้ว x (y คือจำนวนแถวและ x คือจำนวนคอลัมน์)
Brian Hamill

6
ฉันพยายามหลีกเลี่ยง cv2 มันสลับขนาดและโหลดในรูปแบบช่อง BGR ฉันชอบskimage.io.imread('image.jpg')และskimage.transform.resize(img). scikit-image.org/docs/dev/install.html
Eduardo Pignatelli

1
@EduardoPignatelli ฉันหลีกเลี่ยง skimage.transform.resize เพราะคุณไม่สามารถควบคุมอัลกอริทึมการแก้ไขที่ใช้ แต่นั่นอาจไม่สำคัญขึ้นอยู่กับกรณีการใช้งานของผู้คน
Decker

2
@Decker skimage.transform.resize ให้การควบคุมบางอย่างผ่านพารามิเตอร์ 'order'' order = 0 คือเพื่อนบ้านที่ใกล้ที่สุด 1 = bi-linear, 2 = bi-quadratic, 3 = bi-cubic เป็นต้นอย่างไรก็ตามไม่มีค่าเฉลี่ยพื้นที่หรือการแก้ไข lanczos
Tapio

1
@TapioFriberg อ่าใช่ฉันยืนแก้ไข; ฉันเห็นอัลกอริทึมที่กำหนดไว้ในเอกสารสำหรับพารามิเตอร์ 'order' ของ skimage.transform.warp ในบางจุดอาจเป็นประโยชน์ในการอัปเดตเอกสารเพื่อรวมการอ้างอิงสำหรับประเภทตัวอย่างเช่น "Bi-quartic" ไม่ได้กำหนดไว้ที่อื่นในเอกสาร (ณ วันที่ 10 ธันวาคม 2019) - ซับเดียวอาจ เป็นประโยชน์ต่อผู้ใช้ในอนาคต
Decker

67

แม้ว่าอาจเป็นไปได้ที่จะใช้ numpy เพียงอย่างเดียวเพื่อทำสิ่งนี้ แต่การดำเนินการนี้ไม่ได้อยู่ในตัว ที่กล่าวว่าคุณสามารถใช้scikit-image(ซึ่งสร้างขึ้นจากตัวเลข) เพื่อทำการปรับแต่งภาพประเภทนี้

Scikit ภาพเอกสาร rescaling เป็นที่นี่

ตัวอย่างเช่นคุณสามารถทำสิ่งต่อไปนี้กับรูปภาพของคุณ:

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

การดำเนินการนี้จะดูแลสิ่งต่างๆเช่นการแก้ไขการลบรอยหยัก ฯลฯ ให้กับคุณ


2
ขอบคุณ! คำตอบนี้ใช้ได้เช่นกัน! แม้ว่าฉันจะมีปัญหากับanti_aliasingแฟล็ก
Brian Hamill

8
สิ่งนี้จะคืนค่ารูปภาพเป็นfloat ndarray แม้ว่าภาพต้นฉบับของคุณจะเป็นuint8 ก็ตาม
sziraqui

3
นี่เป็นเทคนิคที่ดีเพราะใช้ได้กับช่องต่างๆ ฉันลองใช้ข้อมูล rgb รวมกับข้อมูลคลาวด์จุดลึกและรักษาความสัมพันธ์อย่างที่ฉันต้องการ
Darth Egregious

@DarthEgregious, jakevdp -> มันทำให้ข้อมูลสัญญาณรบกวนแบบสุ่มของฉันเป็นสีเดียวเมื่อฉันปรับขนาดอาร์เรย์ (137,236,3) เป็น (64,64) เหมือนวิธีที่คุณอธิบาย เป็นเรื่องปกติเพราะดูเหมือนว่าข้อมูลทั้งหมดจะสูญหายไปหรือไม่?
Deshwal

1
ไม่ควรเป็น (64,64,3)
Darth Egregious

14

สำหรับผู้ที่มาที่นี่จาก Google ที่กำลังมองหาวิธีที่รวดเร็วในการลดขนาดรูปภาพในnumpyอาร์เรย์เพื่อใช้ในแอปพลิเคชัน Machine Learning นี่เป็นวิธีที่รวดเร็วมาก (ดัดแปลงจากที่นี่ ) วิธีนี้ใช้ได้เฉพาะเมื่อขนาดอินพุตเป็นหลายมิติของเอาต์พุต

ตัวอย่างต่อไปนี้ลดขนาดจาก 128x128 เป็น 64x64 (สามารถเปลี่ยนแปลงได้ง่าย)

ช่องทางการสั่งซื้อล่าสุด

# 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)

ช่องทางการสั่งซื้อครั้งแรก

# 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)

สำหรับภาพโทนสีเทาให้เปลี่ยน3เป็น1แบบนี้:

ช่องทางการสั่งซื้อครั้งแรก

# 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)

วิธีนี้ใช้การรวมสูงสุดที่เทียบเท่า เป็นวิธีที่เร็วที่สุดในการทำสิ่งนี้ที่ฉันพบ


4
large_image [:, :: 2, :: 2] ส่งคืนรูปภาพที่มีความละเอียดลดลงครึ่งหนึ่ง
L.Kärkkäinen

1
@ LasseKärkkäinen แต่มันไม่ได้ลดลงเพียงแค่เลือกพิกเซลอื่น ๆ ความแตกต่างคือฟังก์ชันสุดท้าย 'max' สามารถเปลี่ยนเพื่อเลือกหรือคำนวณพิกเซลได้ดีกว่าเล็กน้อย (เช่นใช้ 'min' หรือ 'mean') วิธีการของคุณมีประโยชน์ (และเร็วกว่า) หากไม่สำคัญ
Waylon Flinn

@ L.Kärkkäinenตรงกันข้ามกับความละเอียดสองเท่าคืออะไร?
rayzinnz

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

11

หากใครมาที่นี่แล้วกำลังมองหาวิธีง่ายๆในการปรับขนาด / ปรับขนาดภาพใน Python โดยไม่ต้องใช้ไลบรารีเพิ่มเติมนี่คือฟังก์ชั่นปรับขนาดรูปภาพที่เรียบง่ายมาก:

#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)]

ตัวอย่างการใช้งาน: การปรับขนาดภาพ (30 x 30) เป็น (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))

เอาท์พุต: ภาพที่ปรับขนาด

วิธีนี้ใช้เพื่อย่อ / ปรับขนาดภาพและทำงานได้ดีกับอาร์เรย์จำนวนนับ


4

imresize()วิธีการของ SciPy เป็นอีกวิธีการปรับขนาด แต่จะถูกลบออกโดยเริ่มจาก SciPy v 1.3.0 SciPy หมายถึงวิธีการปรับขนาดภาพPIL :Image.resize(size, resample=0)

ขนาด - ขนาดที่ร้องขอเป็นพิกเซลเป็น 2 ทูเพิล: (กว้าง, สูง)
resample - ตัวกรองการสุ่มตัวอย่างที่เป็นทางเลือก อาจเป็นหนึ่งใน PIL.Image.NEAREST (ใช้เพื่อนบ้านที่ใกล้ที่สุด), PIL.Image.BILINEAR (การแก้ไขเชิงเส้น), PIL.Image.BICUBIC (การแก้ไขเส้นโค้งแบบลูกบาศก์) หรือ PIL.Image.LANCZOS (ตัวกรองการสุ่มตัวอย่างคุณภาพสูง ). หากละเว้นหรือหากภาพมีโหมด“ 1” หรือ“ P” จะมีการตั้งค่า PIL.Image.NEAREST

ลิงก์ที่นี่: https://pillow.readthedocs.io/en/3.1.x/reference/Image.html#PIL.Image.Image.resize


3
น่าเสียดายที่ imresize () เลิกใช้งานแล้วจะถูกลบออกใน SciPy 1.3.0
MiniQuark

1

มีไลบรารีใดบ้างที่ทำสิ่งนี้ใน numpy / SciPy

แน่นอน คุณสามารถทำได้โดยไม่ต้องใช้ OpenCV, scikit-image หรือ PIL

โดยพื้นฐานแล้วการปรับขนาดภาพเป็นการจับคู่พิกัดของแต่ละพิกเซลจากภาพต้นฉบับไปยังตำแหน่งที่ปรับขนาด

เนื่องจากพิกัดของรูปภาพต้องเป็นจำนวนเต็ม (คิดว่าเป็นเมทริกซ์) หากพิกัดที่แมปมีค่าทศนิยมคุณควรสอดแทรกค่าพิกเซลเพื่อประมาณค่าเป็นตำแหน่งจำนวนเต็ม (เช่นการกำหนดพิกเซลที่ใกล้ที่สุดไปยังตำแหน่งนั้น เป็นการแก้ไขเพื่อนบ้านที่ใกล้ที่สุด )

สิ่งที่คุณต้องมีคือฟังก์ชั่นที่จะทำการแก้ไขนี้ให้กับคุณ SciPy interpolate.interp2dมี

คุณสามารถใช้เพื่อปรับขนาดรูปภาพในอาร์เรย์จำนวนนับได้arrดังนี้:

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))

แน่นอนว่าหากรูปภาพของคุณเป็น RGB คุณต้องทำการแก้ไขสำหรับแต่ละช่อง

หากคุณต้องการที่จะเข้าใจมากขึ้นผมขอแนะนำให้ดูการปรับขนาดภาพ - Computerphile


อาจใช้ไม่ได้ตามคำตอบนี้: 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
ยินดีต้อนรับสู่ StackOverflow เยี่ยมมากที่คุณต้องการช่วยเหลือผู้อื่นด้วยการตอบคำถามของพวกเขา อย่างไรก็ตามฉันไม่เห็นว่าคำตอบของคุณเพิ่มมูลค่าอย่างไรเมื่อเทียบกับคำตอบที่มีอยู่แล้วซึ่งใช้อยู่แล้วcv2และใช้ฟังก์ชันปรับขนาดที่เหมาะสมแทนที่จะใช้ฟังก์ชันปรับขนาดแบบ "sub-optimal" ซ้ำซึ่งแย่กว่าการแก้ไขเพื่อนบ้านที่ใกล้ที่สุด
NOhs
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.