Numpy Yeniden Boyutlandırma / Yeniden Ölçeklendirme Resmi


100

Uyuşmuş bir dizi iken bir görüntü alıp görüntünün ölçeğini değiştirmek istiyorum.

Örneğin bir koka-kola şişesinin bu resmine sahibim: şişe-1

Bu, uyuşmuş bir şekil dizisine dönüşür (528, 203, 3)ve bu ikinci görüntünün boyutunu söylemek için bunu yeniden boyutlandırmak istiyorum: şişe-2

Şeklinde olan (140, 54, 3).

Orijinal görüntüyü korurken görüntünün boyutunu belirli bir şekle nasıl değiştirebilirim? Diğer yanıtlar, her iki veya üçüncü satırı çıkarmanızı önerir, ancak benim yapmak istediğim şey, temelde bir resim düzenleyici aracılığıyla, ancak python koduyla resmi küçültmek. Numpy / SciPy'de bunu yapacak kütüphane var mı?


numpy diziniz için kod gösterebilir misiniz?
ShpielMeister


2
@sascha Bağlandığınız sayfaya göre kullanımdan kaldırıldı.
Paul Panzer

@ShpielMeister IntelliJ'in uyuşmuş diziyi tam olarak yazdırmasını sağlayamıyorum, bazı nedenlerden dolayı çıktılar büyük olduğunda her zaman ... koyar, bu yüzden konsoldaki dizi çıktısının yalnızca bir kısmını görebiliyorum
Brian Hamill

Yanıtlar:


125

Evet, yükleyebilir opencv(bu, görüntü işleme ve bilgisayar görüşü için kullanılan bir kitaplıktır) ve cv2.resizeişlevi kullanabilirsiniz . Ve örneğin şunu kullanın:

import cv2
import numpy as np

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

Bu imgnedenle, orijinal görüntüyü resiçeren uyuşmuş bir dizi, yeniden boyutlandırılan görüntüyü içeren uyuşmuş bir dizi . Önemli bir husus, interpolationparametredir: Bir görüntünün nasıl yeniden boyutlandırılacağının birkaç yolu vardır. Özellikle görüntüyü küçülttüğünüz ve orijinal görüntünün boyutu yeniden boyutlandırılan görüntünün boyutunun bir katı olmadığı için. Olası enterpolasyon şemaları şunlardır:

  • INTER_NEAREST - en yakın komşu enterpolasyonu
  • INTER_LINEAR - çift doğrusal enterpolasyon (varsayılan olarak kullanılır)
  • INTER_AREA- piksel alanı ilişkisini kullanarak yeniden örnekleme. Hareli olmayan sonuçlar verdiği için görüntü yok etme için tercih edilen bir yöntem olabilir. Ancak görüntü yakınlaştırıldığında INTER_NEARESTyönteme benzer .
  • INTER_CUBIC - 4x4 piksel çevresinde bikübik enterpolasyon
  • INTER_LANCZOS4 - 8x8 piksel bölgesi üzerinde bir Lanczos enterpolasyonu

Çoğu seçenekte olduğu gibi, her yeniden boyutlandırma şeması için bir stratejinin diğerine tercih edilebileceği senaryolar olması anlamında "en iyi" seçeneği yoktur.


5
Bu kodu yeni denedim ve işe yarıyor! Sadece bir değişiklik olduğunu dsizeolmalıdır dsize=(54, 140)o, Y x alır y gibi bir numpy dizi Şekil şekil olarak zaman x (y satır sayısı kadardır ve x sütun sayısıdır) nereye
Brian Hamili

6
Cv2'den kaçınmaya çalışıyorum, boyutları değiştiriyor ve BGR kanal formatında yüklüyor. Ben tercih skimage.io.imread('image.jpg')ve skimage.transform.resize(img). scikit-image.org/docs/dev/install.html
Eduardo Pignatelli

1
@EduardoPignatelli skimage.transform.resize'den kaçınıyorum çünkü kullandığı enterpolasyon algoritması üzerinde kontrolünüz yok. Ancak, insanların kullanım durumlarına bağlı olarak bu önemli olmayabilir.
Decker

2
@Decker skimage.transform.resize, 'order' parametresi aracılığıyla bir miktar kontrol sağlar. order = 0 en yakın komşu, 1 = bi-lineer, 2 = bi-quadratic, 3 = bi-cubic vs. Ancak alan ortalaması veya lanczos enterpolasyonu yok.
Tapio

1
@TapioFriberg ahh evet, düzeltilmiş duruyorum; Skimage.transform.warp'ın 'order' parametresi için dokümantasyon altında tanımlanan algoritmaları görüyorum. Bir noktada, dokümanları "Bi-quartic" türleri için referanslar içerecek şekilde güncellemek yararlı olabilir, örneğin, dokümantasyonda başka hiçbir yerde tanımlanmamıştır (10 Aralık 2019 itibarıyla) - gelecekteki kullanıcılar için faydalı olacaktır.
Decker

67

Bunu yapmak için tek başına numpy kullanmak mümkün olsa da, işlem yerleşik değildir. Bununla birlikte, scikit-imagebu tür görüntü manipülasyonunu yapmak için (numpy üzerine kurulu olan) kullanabilirsiniz.

Scikit-Image yeniden ölçekleme belgeleri burada .

Örneğin, resminizle aşağıdakileri yapabilirsiniz:

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

Bu sizin için enterpolasyon, kenar yumuşatma, vb. Gibi şeylerle ilgilenecektir.


2
Teşekkür ederim! Bu cevap da işe yarıyor! anti_aliasingBayrakla ilgili bazı sorunlar yaşıyor olsam da
Brian Hamill

8
Bu döner görüntü olarak şamandıra orijinal görüntü olsa bile ndarray uint8
sziraqui

3
Bu güzel bir teknik çünkü herhangi bir sayıda kanalla çalışıyor. Bunu bir derinlik noktası bulutu verisi ile birleştirilen rgb verisi ile denedim ve istediğim gibi ilişkiyi korudu.
Darth Egregious

@DarthEgregious, jakevdp -> tanımladığınız yöntem gibi (137,236,3) diziyi (64,64) olarak yeniden boyutlandırdığımda rastgele gürültü verilerimi tek renge dönüştürdü. Bu, tüm bilgileri kaybetmiş gibi göründüğü için normal mi?
Deshwal

1
Olmamalı (64,64,3)
Darth Egregious

15

Google'dan buraya gelen numpyve Makine Öğrenimi uygulamalarında kullanmak üzere dizilerdeki görüntüleri alt örneklemenin hızlı bir yolunu arayan kişiler için işte süper hızlı bir yöntem ( buradan uyarlanmıştır ). Bu yöntem yalnızca girdi boyutları çıktı boyutlarının bir katı olduğunda çalışır.

Aşağıdaki örnekler 128x128'den 64x64'e alt örnekleme (bu kolayca değiştirilebilir).

Son sipariş veren kanallar

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

İlk sipariş veren kanallar

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

Gri tonlamalı görüntüler için 3aşağıdaki 1gibi değiştirin :

İlk sipariş veren kanallar

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

Bu yöntem, maksimum havuzlamanın eşdeğerini kullanır. Bulduğum bunu yapmanın en hızlı yolu.


4
large_image [:, :: 2, :: 2], çözünürlüğü yarıya indirilmiş görüntüyü döndürür.
L. Kärkkäinen

1
@ LasseKärkkäinen, ancak altörnekleme yapmaz, yalnızca diğer tüm pikseli seçer. Aradaki fark, son işlev olan 'max', pikselleri biraz daha iyi yöntemlerle seçmek veya hesaplamak için değiştirilebilmesidir (örneğin 'min' veya 'ortalama' kullanılarak). Yönteminiz, önemli değilse yararlıdır (ve daha hızlıdır).
Waylon Flinn

@ L.Kärkkäinen bunun çözünürlüğü ikiye katlamanın tersi nedir?
rayzinnz

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

11

Ek kitaplıklar kullanmadan Python'da bir görüntüyü ölçeklendirmek / yeniden boyutlandırmak için basit bir yöntem arayan biri buraya geldiyse, işte çok basit bir görüntü yeniden boyutlandırma işlevi:

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

Örnek kullanım: (30 x 30) bir görüntüyü (100 x 200) olarak yeniden boyutlandırma:

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

Çıktı: ölçekli görüntü

Bu, görüntüleri küçültmek / ölçeklendirmek için çalışır ve numpy dizilerle iyi çalışır.


4

SciPy'nin imresize()yöntemi başka bir yeniden boyutlandırma yöntemiydi, ancak SciPy v 1.3.0'dan itibaren kaldırılacak. SciPy, PIL görüntüsünü yeniden boyutlandırma yöntemini ifade eder :Image.resize(size, resample=0)

boyut - İstenen boyut, piksel cinsinden, 2'li grup olarak: (genişlik, yükseklik).
yeniden örnekleme - İsteğe bağlı bir yeniden örnekleme filtresi. Bu, PIL.Image.NEAREST (en yakın komşuyu kullan), PIL.Image.BILINEAR (doğrusal enterpolasyon), PIL.Image.BICUBIC (kübik spline enterpolasyonu) veya PIL.Image.LANCZOS (yüksek kaliteli bir alt örnekleme filtresi) olabilir. ). Atlanırsa veya görüntünün modu “1” veya “P” ise, PIL.Image.NEAREST olarak ayarlanır.

Buraya bağlantı verin: https://pillow.readthedocs.io/en/3.1.x/reference/Image.html#PIL.Image.Image.resize


3
Maalesef imresize () kullanımdan kaldırıldı,
SciPy

1

Numpy / SciPy'de bunu yapacak kütüphane var mı

Elbette. Bunu OpenCV, scikit-image veya PIL olmadan yapabilirsiniz.

Görüntü yeniden boyutlandırma, temel olarak her pikselin koordinatlarını orijinal görüntüden yeniden boyutlandırılan konumuna eşlemektir.

Bir görüntünün koordinatlarının tamsayı olması gerektiğinden (matris olarak düşünün), eşlenen koordinatın ondalık değerleri varsa, piksel değerini tamsayı konumuna yaklaştırmak için enterpolasyon yapmalısınız (örneğin, bu konuma en yakın pikseli elde etmek bilinir olarak en yakın komşu interpolasyon ).

Tek ihtiyacınız olan, bu enterpolasyonu sizin için yapan bir işlevdir. SciPy vardır interpolate.interp2d.

Bunu, arraşağıdaki gibi , numpy dizisindeki bir görüntüyü yeniden boyutlandırmak için kullanabilirsiniz :

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

Elbette, görüntünüz RGB ise, her kanal için enterpolasyon yapmanız gerekir.

Daha fazlasını anlamak isterseniz, Resizing Images - Computerphile'ı izlemenizi öneririm .


Bu yanıta dayalı olarak çalışmayabilir: 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'a hoş geldiniz. Başkalarının sorularını yanıtlayarak yardım etmek istemeniz harika. Ancak, cv2en yakın komşu enterpolasyonundan daha kötü olan bir "optimalin altında" yeniden boyutlandırma işlevini yeniden uygulamak yerine, halihazırda uygun bir yeniden boyutlandırma işlevini kullanan ve kullanan mevcut yanıtla karşılaştırıldığında yanıtınızın nasıl değer kattığını anlamıyorum .
NOhs
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.