Come posso rendere più nitida un'immagine in OpenCV?


Risposte:


160

Una procedura generale è illustrata nell'articolo di Wikipedia sul mascheramento di contrasto :

Si utilizza un filtro di levigatura gaussiano e si sottrae la versione levigata dall'immagine originale (in modo ponderato in modo che i valori di un'area costante rimangano costanti).

Per ottenere una versione più nitida di frameinto image: (both cv::Mat)

cv::GaussianBlur(frame, image, cv::Size(0, 0), 3);
cv::addWeighted(frame, 1.5, image, -0.5, 0, image);

I parametri sono qualcosa che devi regolare da solo.

C'è anche lo sharpening laplaciano, dovresti trovare qualcosa su quello quando cerchi su google.


1
C'è un modo per replicare il risultato di Photoshop di Maschera di contrasto?
Royi

@Drazick Stai chiedendo perché non può essere replicato? link a wikipedia è stato fornito sopra. digital_unsharp_masking per essere precisi
tilaprimera

@tilaprimera, lo chiedo perché USM di Photoshop è diverso dall'USM "classico".
Royi

50

Puoi provare un semplice kernel e la funzione filter2D , ad esempio in Python:

kernel = np.array([[-1,-1,-1], [-1,9,-1], [-1,-1,-1]])
im = cv2.filter2D(im, -1, kernel)

Wikipedia ha una buona panoramica dei kernel con alcuni altri esempi qui - https://en.wikipedia.org/wiki/Kernel_(image_processing)

Nell'elaborazione delle immagini, un kernel, una matrice di convoluzione o una maschera è una piccola matrice. Viene utilizzato per la sfocatura, la nitidezza, la goffratura, il rilevamento dei bordi e altro ancora. Ciò si ottiene eseguendo una convoluzione tra un kernel e un'immagine.


14

Puoi trovare un codice di esempio sulla nitidezza dell'immagine utilizzando l'algoritmo "maschera di contrasto" nella documentazione di OpenCV .

Modifica dei valori di sigma, threshold, amountdarà risultati diversi.

// sharpen image using "unsharp mask" algorithm
Mat blurred; double sigma = 1, threshold = 5, amount = 1;
GaussianBlur(img, blurred, Size(), sigma, sigma);
Mat lowContrastMask = abs(img - blurred) < threshold;
Mat sharpened = img*(1+amount) + blurred*(-amount);
img.copyTo(sharpened, lowContrastMask);

Questo è bellissimo!
roosevelt

12

È possibile rendere più nitida un'immagine utilizzando una maschera di contrasto . Puoi trovare ulteriori informazioni sulla maschera di contrasto qui . Ed ecco un'implementazione di Python che utilizza OpenCV:

import cv2 as cv
import numpy as np

def unsharp_mask(image, kernel_size=(5, 5), sigma=1.0, amount=1.0, threshold=0):
    """Return a sharpened version of the image, using an unsharp mask."""
    blurred = cv.GaussianBlur(image, kernel_size, sigma)
    sharpened = float(amount + 1) * image - float(amount) * blurred
    sharpened = np.maximum(sharpened, np.zeros(sharpened.shape))
    sharpened = np.minimum(sharpened, 255 * np.ones(sharpened.shape))
    sharpened = sharpened.round().astype(np.uint8)
    if threshold > 0:
        low_contrast_mask = np.absolute(image - blurred) < threshold
        np.copyto(sharpened, image, where=low_contrast_mask)
    return sharpened

def example():
    image = cv.imread('my-image.jpg')
    sharpened_image = unsharp_mask(image)
    cv.imwrite('my-sharpened-image.jpg', sharpened_image)

questa sembra essere una versione piuttosto pratica. potresti aggiungere qualche informazione in più sui parametri. la dimensione del kernel e il sigma possono essere cercati in opencv, ma per quanto riguarda quantità e soglia? Grazie!
scelta

2
@choise amountè semplicemente la quantità di nitidezza. Ad esempio, un valore amountdi 2.0 fornisce un'immagine più nitida rispetto al valore predefinito di 1.0. thresholdè la soglia per la maschera a basso contrasto. In altre parole, i pixel per i quali la differenza tra le immagini in ingresso e quelle sfocate è inferiore thresholdrimarranno invariati.
Soroush

10

Qualsiasi immagine è una raccolta di segnali di varie frequenze. Le frequenze più alte controllano i bordi e le frequenze più basse controllano il contenuto dell'immagine. I bordi si formano quando c'è una transizione netta da un valore di pixel all'altro valore di pixel come 0 e 255 nella cella adiacente. Ovviamente c'è un brusco cambiamento e quindi il bordo e l'alta frequenza. Per rendere più nitida un'immagine, queste transizioni possono essere ulteriormente migliorate.

Un modo è convolgere un kernel di filtro autocostruito con l'immagine.

    import cv2
    import numpy as np

    image = cv2.imread('images/input.jpg')
    kernel = np.array([[-1,-1,-1], 
                       [-1, 9,-1],
                       [-1,-1,-1]])
    sharpened = cv2.filter2D(image, -1, kernel) # applying the sharpening kernel to the input image & displaying it.
    cv2.imshow('Image Sharpening', sharpened)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

Esiste un altro metodo per sottrarre una versione sfocata dell'immagine dalla versione brillante di essa. Questo aiuta a rendere più nitida l'immagine. Ma dovrebbe essere fatto con cautela poiché stiamo solo aumentando i valori dei pixel. Immagina un valore di pixel in scala di grigi 190, che se moltiplicato per un peso di 2 diventa 380, ma viene ridotto a 255 a causa della gamma di pixel massima consentita. Questa è la perdita di informazioni e porta a un'immagine sbiadita.

    addWeighted(frame, 1.5, image, -0.5, 0, image);

5

Per chiarezza in questo argomento, è necessario sottolineare alcuni punti:

  1. La nitidezza delle immagini è un problema mal posto. In altre parole, la sfocatura è un'operazione con perdita e in generale non è possibile tornare indietro.

  2. Per rendere più nitide le singole immagini, è necessario in qualche modo aggiungere vincoli (ipotesi) sul tipo di immagine che si desidera e su come è diventata sfocata. Questa è l'area delle statistiche delle immagini naturali. Gli approcci per fare la nitidezza mantengono queste statistiche esplicitamente o implicitamente nei loro algoritmi (il deep learning è il più implicitamente codificato). L'approccio comune di aumentare il peso di alcuni livelli di una decomposizione di una piramide DOG o laplaciana , che è la generalizzazione della risposta di Brian Burns, presuppone che una sfocatura gaussiana abbia corrotto l'immagine e il modo in cui viene eseguita la ponderazione è collegato alle ipotesi su ciò che era nell'immagine per cominciare.

  3. Altre fonti di informazione possono rendere il problema della nitidezza ben posto. Tali fonti di informazioni comuni sono il video di un oggetto in movimento o l'impostazione multi-visualizzazione. L'affilatura in quell'impostazione è solitamente chiamata super-risoluzione (che è un nome molto brutto per questo, ma è rimasto nei circoli accademici). Ci sono stati metodi di super risoluzione in OpenCV da molto tempo ... anche se di solito non funzionano così bene per problemi reali l'ultima volta che li ho controllati. Mi aspetto che anche il deep learning abbia prodotto dei risultati meravigliosi. Forse qualcuno pubblicherà commenti su ciò che è utile là fuori.


3

Per rendere più nitida un'immagine possiamo usare il filtro (come in molte risposte precedenti)

kernel = np.array([[-1, -1, -1],[-1, 8, -1],[-1, -1, 0]], np.float32) 

kernel /= denominator * kernel

Sarà il massimo quando il denominatore è 1 e diminuirà all'aumentare (2.3 ..)

Il più utilizzato è quando il denominatore è 3.

Di seguito è riportata l'implementazione.

kernel = np.array([[-1, -1, -1],[-1, 8, -1],[-1, -1, 0]], np.float32) 

kernel = 1/3 * kernel

dst = cv2.filter2D(image, -1, kernel)

Qualcosa sembra mancare vicino a "Sarà il massimo" .
Peter Mortensen

Sì Peter, grazie!
kaustubhd9

-4

Prova con questo:

cv::bilateralFilter(img, 9, 75, 75);

Potresti trovare maggiori informazioni qui .


9
La domanda riguarda la nitidezza dell'immagine, non la levigatura che preserva i bordi.
Michael Burdinov
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.