Jak mogę wyostrzyć obraz w OpenCV?

122

Jak mogę wyostrzyć obraz za pomocą OpenCV ?

Istnieje wiele sposobów wygładzania lub rozmywania, ale żaden z nich nie byłby możliwy do wyostrzenia.

AruniRC
źródło

Odpowiedzi:

160

Jedna ogólna procedura została opisana w artykule Wikipedii dotyczącym nieostrego maskowania :

Używasz filtru wygładzającego Gaussa i odejmujesz wygładzoną wersję od oryginalnego obrazu (w sposób ważony, aby wartości stałego obszaru pozostały stałe).

Aby uzyskać zaostrzoną wersję framew image: (oba cv::Mat)

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

Parametry są coś, co musisz dostosować dla siebie.

Jest też ostrzenie Laplacian, powinieneś znaleźć coś na ten temat, gdy szukasz Google.

etarion
źródło
1
Czy istnieje sposób na odtworzenie wyniku działania maski wyostrzającej w Photoshopie?
Royi
@Drazick Pytasz, ponieważ nie można go replikować? link do wikipedii został podany powyżej. digital_unsharp_masking by być konkretnym
tilaprimera
@tilaprimera, pytam, ponieważ USM Photoshopa różni się od "klasycznego" USM.
Royi
50

Możesz wypróbować proste jądro i funkcję filter2D , np. W Pythonie:

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

Wikipedia zawiera dobry przegląd jąder z kilkoma przykładami tutaj - https://en.wikipedia.org/wiki/Kernel_(image_processing)

W przetwarzaniu obrazu jądro, macierz splotu lub maska ​​to mała macierz. Służy do rozmycia, wyostrzania, wytłaczania, wykrywania krawędzi i nie tylko. Osiąga się to poprzez zrobienie splotu między jądrem a obrazem.

Brian Burns
źródło
14

Przykładowy kod dotyczący wyostrzania obrazu przy użyciu algorytmu „maski wyostrzającej” można znaleźć w dokumentacji OpenCV .

Zmiana wartości sigma, threshold, amountdadzą różne wyniki.

// 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);
Sturkmen
źródło
To jest piękne!
roosevelt
12

Obraz można wyostrzyć, używając maski wyostrzającej . Więcej informacji na temat nieostrego maskowania można znaleźć tutaj . A oto implementacja Pythona przy użyciu 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)
Soroush
źródło
wydaje się, że jest to całkiem przydatna wersja. czy mógłbyś dodać trochę więcej informacji o parametrach. rozmiar jądra i sigma można sprawdzić w opencv, ale co z ilością i progiem? Dzięki!
wybierz
2
@choise amountto po prostu stopień wyostrzenia. Na przykład wartość amount2,0 daje ostrzejszy obraz w porównaniu z domyślną wartością 1,0. thresholdjest progiem dla maski o niskim kontraście. Innymi słowy, piksele, dla których różnica między obrazem wejściowym a rozmazanymi obrazami jest mniejsza niż thresholdpozostaną niezmienione.
Soroush
11

Dowolny obraz to zbiór sygnałów o różnych częstotliwościach. Wyższe częstotliwości kontrolują krawędzie, a niższe częstotliwości kontrolują zawartość obrazu. Krawędzie są tworzone, gdy występuje ostre przejście od wartości jednego piksela do wartości drugiego piksela, np. 0 i 255 w sąsiedniej komórce. Oczywiście następuje gwałtowna zmiana, a tym samym krawędź i wysoka częstotliwość. W celu wyostrzenia obrazu przejścia te można dodatkowo wzmocnić.

Jednym ze sposobów jest połączenie z obrazem samodzielnie utworzonego jądra filtru.

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

Istnieje inna metoda odejmowania zamazanej wersji obrazu od jego jasnej wersji. Pomaga to wyostrzyć obraz. Należy jednak zachować ostrożność, ponieważ po prostu zwiększamy wartości pikseli. Wyobraź sobie wartość 190 pikseli w skali szarości, która pomnożona przez wagę 2 daje 380, ale jest zmniejszona do 255 ze względu na maksymalny dopuszczalny zakres pikseli. To utrata informacji i prowadzi do wyblaknięcia obrazu.

    addWeighted(frame, 1.5, image, -0.5, 0, image);
Ujjwal Saxena
źródło
5

Dla jasności w tym temacie należy zwrócić uwagę na kilka kwestii:

  1. Wyostrzanie obrazów to źle postawiony problem. Innymi słowy, rozmycie jest operacją stratną, a powrót z niej na ogół nie jest możliwy.

  2. Aby wyostrzyć pojedyncze obrazy, musisz w jakiś sposób dodać ograniczenia (założenia) dotyczące tego, jakiego rodzaju obrazu chcesz i jak się rozmyło. To jest obszar statystyki obrazu naturalnego. Podejścia do wyostrzania zawierają te statystyki jawnie lub niejawnie w swoich algorytmach (głębokie uczenie jest najbardziej niejawnie zakodowane). Powszechne podejście polegające na zwiększaniu wagi niektórych poziomów rozkładu piramidy Psa lub Laplaciana , które jest uogólnieniem odpowiedzi Briana Burnsa, zakłada, że ​​rozmycie Gaussa zepsuło obraz, a sposób ważenia jest powiązany z założeniami dotyczącymi tego, co było na obrazku.

  3. Inne źródła informacji mogą sprawić, że problem z ostrzeniem będzie słuszny. Typowymi źródłami informacji są wideo poruszającego się obiektu lub ustawienia wielu widoków. Wyostrzanie w tym ustawieniu jest zwykle nazywane super rozdzielczością (co jest bardzo złym określeniem, ale utknęło w kręgach akademickich). Nastąpił metody super-rozdzielczości w OpenCV od dawna .... choć zwykle nie pracuję, że dobrze na rzeczywiste problemy ostatnio sprawdziłem je. Spodziewam się, że głębokie uczenie się również przyniosło wspaniałe rezultaty. Może ktoś napisze w uwagach o tym, co jest warte zachodu.

Stefan Karlsson
źródło
3

Aby wyostrzyć obraz, możemy użyć filtra (jak w wielu poprzednich odpowiedziach)

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

kernel /= denominator * kernel

Najwięcej będzie, gdy mianownik będzie wynosił 1 i będzie maleć wraz ze wzrostem (2,3 ...)

Najczęściej używany jest, gdy mianownik to 3.

Poniżej znajduje się realizacja.

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

kernel = 1/3 * kernel

dst = cv2.filter2D(image, -1, kernel)
kaustubhd9
źródło
Wydaje się, że czegoś brakuje w pobliżu „To będzie najbardziej” .
Peter Mortensen
Tak, Peter, dziękuję!
kaustubhd9
-4

Spróbuj z tym:

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

Więcej informacji znajdziesz tutaj .

mch
źródło
9
Pytanie dotyczy wyostrzania obrazu, a nie wygładzania z zachowaniem krawędzi.
Michael Burdinov,