Asosiy qismga o'tish

Filtrlash: shovqinni olib tashlash

7-bob 5 kod bloki 1503 so'z

Shovqin qayerdan keladi

Kam yorug'likda olingan surat, arzon kamera, uzoq masofadan yuborilgan video — hammasida shovqin bor. Shovqin keyingi qadamlarni buzadi: chekka topish soxta chiziqlar ko'radi, kontur mayda bo'laklarga bo'linadi, OCR harflarni chalkashtiradi.

Ikki xil shovqin bilan ishlaymiz: gauss (har pikselga kichik tasodifiy qo'shimcha) va tuz-qalampir (ba'zi piksellar butunlay oq yoki qora). Bizda ikkalasi ham bor:

python7 qator
toza = cv2.imread(str(RASM / "shakllar.png"))
shovqinli = cv2.imread(str(RASM / "shovqinli.png"))
farq = np.abs(toza.astype(np.int16) - shovqinli.astype(np.int16))
print(f"o'rtacha farq: {farq.mean():.1f} | eng katta farq: {farq.max()}")
print(f"butunlay oq yoki qora bo'lib qolgan piksellar: {100 * ((shovqinli == 0) | (shovqinli == 255)).all(axis=2).mean():.1f}%")
ko_rsat(toza, shovqinli, nom="shovqin.png", sarlavhalar=["toza (asl)", "shovqinli"],
        izoh="Gauss shovqini — umumiy 'g'adir-budurlik'; tuz-qalampir — yakka oq va qora nuqtalar.")
Chiqish
o'rtacha farq: 16.6 | eng katta farq: 245
butunlay oq yoki qora bo'lib qolgan piksellar: 5.7%

Gauss shovqini — umumiy 'g'adir-budurlik'; tuz-qalampir — yakka oq va qora nuqtalar.

Gauss shovqini — umumiy 'g'adir-budurlik'; tuz-qalampir — yakka oq va qora nuqtalar.

Bizda haqiqat bor: shakllar.png — asl, toza rasm. Demak har filtrning natijasini u bilan solishtirib, qaysi biri yaxshiroq ekanini o'lchash mumkin, "menimcha chiroyliroq" demasdan.

To'rtta filtr

python23 qator
import time
filtrlar = {
    "blur (o'rtacha)": lambda im: cv2.blur(im, (5, 5)),
    "GaussianBlur":    lambda im: cv2.GaussianBlur(im, (5, 5), 0),
    "medianBlur":      lambda im: cv2.medianBlur(im, 5),
    "bilateralFilter": lambda im: cv2.bilateralFilter(im, 9, 75, 75),
}
natijalar, qatorlar = {}, []
for nom, f in filtrlar.items():
    t0 = time.perf_counter()
    for _ in range(10):
        chiqdi = f(shovqinli)
    ms = (time.perf_counter() - t0) / 10 * 1000
    natijalar[nom] = chiqdi
    xato = float(np.abs(toza.astype(np.int16) - chiqdi.astype(np.int16)).mean())
    psnr = cv2.PSNR(toza, chiqdi)
    qatorlar.append({"filtr": nom, "vaqt, ms": round(ms, 2), "asldan farq": round(xato, 2), "PSNR, dB": round(psnr, 1)})
qatorlar.append({"filtr": "(filtrsiz)", "vaqt, ms": 0,
                 "asldan farq": round(float(np.abs(toza.astype(np.int16) - shovqinli.astype(np.int16)).mean()), 2),
                 "PSNR, dB": round(cv2.PSNR(toza, shovqinli), 1)})
show(pd.DataFrame(qatorlar))
ko_rsat(*natijalar.values(), nom="filtrlar.png", sarlavhalar=list(natijalar), kenglik=15,
        izoh="To'rt filtr, bitta shovqinli rasm. Farqni chekkalarga va yakka nuqtalarga qarab baholang.")
filtrvaqt, msasldan farqPSNR, dB
blur (o'rtacha)0.188.5326.1
GaussianBlur0.238.6725.6
medianBlur1.314.0133.1
bilateralFilter17.117.8217.8
(filtrsiz)016.5617

To'rt filtr, bitta shovqinli rasm. Farqni chekkalarga va yakka nuqtalarga qarab baholang.

To'rt filtr, bitta shovqinli rasm. Farqni chekkalarga va yakka nuqtalarga qarab baholang.

PSNR (peak signal-to-noise ratio) — asl bilan qanchalik mos kelishini dB da o'lchaydi: katta bo'lsa yaxshiroq. Har 6 dB taxminan "ikki barobar aniqroq" degani.

Jadvaldan ko'rinadi: medianBlur tuz-qalampir shovqinida yutadi — PSNR 33.1 dB, boshqalari 26 dB atrofida. Sababi oddiy: u atrofdagi 25 pikselni tartiblab, o'rtadagisini oladi. Yakka oq nuqta (255) tartiblanganda chetga tushadi va tanlanmaydi. O'rtacha oluvchi filtrlar (blur, GaussianBlur) esa o'sha 255 ni hisobga qo'shadi va nuqtani "yoyib" yuboradi — dog' kichrayadi, lekin yo'qolmaydi.

Endi jadvaldagi eng qiziq qatorga qarang: bilateralFilter — 17.8 dB, filtrsiz rasm esa 17.0 dB. Ya'ni eng qimmat filtr (17.7 ms, boshqalaridan o'n barobar sekin) deyarli hech narsa qilmadi. Bu xato emas, uning tabiati: bilateral filtr chekkani saqlaydi, tuz-qalampirdagi har bir yakka nuqta esa uning uchun o'tkir chekka — demak u saqlanadi.

Saboq: filtrni "yaxshi" yoki "yomon" deb emas, shovqin turiga mos yoki mos emas deb tanlang. Keyingi bo'limda bilateral o'z ishini qiladigan holatni ko'ramiz.

Yadro (kernel) o'lchami nimani o'zgartiradi

python10 qator
qatorlar = []
for k in (3, 5, 9, 15):
    g = cv2.GaussianBlur(shovqinli, (k, k), 0)
    m = cv2.medianBlur(shovqinli, k)
    qatorlar.append({"yadro": f"{k}x{k}", "Gauss PSNR": round(cv2.PSNR(toza, g), 1),
                     "Median PSNR": round(cv2.PSNR(toza, m), 1)})
show(pd.DataFrame(qatorlar))
ko_rsat(cv2.GaussianBlur(shovqinli, (3, 3), 0), cv2.GaussianBlur(shovqinli, (15, 15), 0),
        nom="yadro_olchami.png", sarlavhalar=["Gauss 3x3 — shovqin qoldi", "Gauss 15x15 — chekkalar yo'qoldi"],
        izoh="Yadro kattalashsa shovqin kamayadi, lekin tafsilot ham yo'qoladi. Har doim murosa.")
yadroGauss PSNRMedian PSNR
3x324.230.3
5x525.633.1
9x926.633.9
15x1526.232.1

Yadro kattalashsa shovqin kamayadi, lekin tafsilot ham yo'qoladi. Har doim murosa.

Yadro kattalashsa shovqin kamayadi, lekin tafsilot ham yo'qoladi. Har doim murosa.

Yadro toq bo'lishi kerak (3, 5, 7...), chunki markaz piksel aniq bo'lishi shart. Kattalashtirsangiz: shovqin kamayadi, chekkalar xiralashadi, hisob sekinlashadi.

Bilateral: chekkani saqlaydigan filtr

Oddiy blur hamma narsani birdek xiralashtiradi. Bilateral filtr ikki narsani hisobga oladi: piksellar qanchalik yaqin (masofa) va qanchalik o'xshash (rang). Rangi keskin farq qiladigan qo'shni — ya'ni chekka — o'rtachalashga qo'shilmaydi.

python9 qator
img = cv2.imread(str(RASM / "qurilish_kichik.jpg"))
g = cv2.GaussianBlur(img, (9, 9), 0)
b = cv2.bilateralFilter(img, 9, 90, 90)
def keskinlik(im):
    return round(float(cv2.Laplacian(cv2.cvtColor(im, cv2.COLOR_BGR2GRAY), cv2.CV_64F).var()))
print(f"keskinlik — asl: {keskinlik(img)}, Gauss: {keskinlik(g)}, bilateral: {keskinlik(b)}")
ko_rsat(img[180:400, 280:620], g[180:400, 280:620], b[180:400, 280:620], nom="bilateral.png",
        sarlavhalar=["asl", "GaussianBlur 9x9", "bilateralFilter"],
        izoh="Bilateral tekis joylarni silliqlaydi, chekkalarni esa saqlaydi — shuning uchun keskinlik yuqori qoladi.")
Chiqish
keskinlik — asl: 2038, Gauss: 16, bilateral: 1231

Bilateral tekis joylarni silliqlaydi, chekkalarni esa saqlaydi — shuning uchun keskinlik yuqori qoladi.

Bilateral tekis joylarni silliqlaydi, chekkalarni esa saqlaydi — shuning uchun keskinlik yuqori qoladi.

Narxi — tezlik: bilateral yuqoridagi jadvalda eng sekin filtr edi. Video uchun har kadrda ishlatish qimmat.

:::tip Qaysi filtrni qachon Tuz-qalampir (yakka nuqtalar) → medianBlur. Umumiy g'adir-budurlik → GaussianBlur. Chekka muhim, teksturani tozalash kerak (portret, skan) → bilateralFilter. Tezlik hammasidan muhim → blur. Shovqin yo'q bo'lsa — hech qanday filtr ishlatmang. :::

Filtr chekkada nima qiladi

Yadro rasm chekkasiga yetganda tashqarida piksel yo'q. OpenCV ularni "o'ylab topadi":

python6 qator
kichik = cv2.resize(toza, (200, 150))
turlar = {"REFLECT (default)": cv2.BORDER_REFLECT, "CONSTANT (qora)": cv2.BORDER_CONSTANT,
          "REPLICATE": cv2.BORDER_REPLICATE}
rasmlar = [cv2.GaussianBlur(kichik, (31, 31), 0, borderType=t) for t in turlar.values()]
ko_rsat(*rasmlar, nom="filtr_chegara.png", sarlavhalar=list(turlar),
        izoh="Katta yadroda farq ko'rinadi: CONSTANT chekkani qoraytiradi, REFLECT tabiiyroq.")

Katta yadroda farq ko'rinadi: CONSTANT chekkani qoraytiradi, REFLECT tabiiyroq.

Katta yadroda farq ko'rinadi: CONSTANT chekkani qoraytiradi, REFLECT tabiiyroq.

Kichik yadroda farq sezilmaydi, katta yadroda chekka bo'ylab qora yo'l paydo bo'lishi mumkin — sababi shu.

Xulosa

Tushuncha Asosiy fikr
PSNR Asl bilan moslikni dB da o'lchaydi; katta — yaxshi
blur Eng tez, eng qo'pol
GaussianBlur Umumiy shovqin uchun standart tanlov
medianBlur Tuz-qalampirni butunlay olib tashlaydi
bilateralFilter Chekkani saqlaydi, lekin sekin
Yadro Toq son; katta — tozaroq, lekin xiraroq
Chegara Katta yadroda borderType sezilarli bo'ladi

Talaba ishi

  1. medianBlur ni faqat gauss shovqini bor rasmda sinang (tuz-qalampirsiz). U hali ham yutadimi? Nega?
  2. bilateralFilter ning sigmaColor ni 10, 50, 150 qilib ko'ring. Qaysi qiymatdan keyin u oddiy blur ga o'xshab qoladi?
  3. Ikki filtrni ketma-ket qo'llang (avval median, keyin gauss). PSNR yaxshilandimi? Tartibni almashtirsangiz-chi?
  4. qurilish.jpg ga sun'iy tuz-qalampir shovqini qo'shing (5% piksel) va to'rt filtrni qayta o'lchang. Haqiqiy fotosuratda tartib o'zgardimi?

Bu bobni bepul o'qidingiz.

Kitob o'rgatadi, lekin sizning kodingiz nega ishlamaganini ayta olmaydi. Kursda uy vazifangiz tekshiriladi.

Telegramda yozish Narxlar