Asosiy qismga o'tish

Chekka topish: Sobel, Laplacian va Canny

8-bob 6 kod bloki 1612 so'z

Chekka nima

Chekka — yorqinlik keskin o'zgaradigan joy. Matematikada bu hosila: qo'shni piksellar farqi katta bo'lsa, o'sha yerda chekka bor. Shuning uchun chekka topish har doim kulrang rasmda bajariladi — rang emas, yorqinlik o'zgarishi muhim.

Chekka nima uchun kerak: kontur topish (10-bob), hujjat burchaklarini aniqlash (17-bob), shakl o'lchash, sifat nazorati (detalda chiziq bormi).

Sobel: yo'nalish bo'yicha hosila

Sobel gorizontal va vertikal o'zgarishni alohida o'lchaydi:

python9 qator
img = cv2.imread(str(RASM / "shakllar.png"), cv2.IMREAD_GRAYSCALE)
sx = cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=3)          # x bo'yicha: vertikal chekkalar
sy = cv2.Sobel(img, cv2.CV_64F, 0, 1, ksize=3)          # y bo'yicha: gorizontal chekkalar
kuch = cv2.magnitude(sx, sy)
print(f"Sobel x: min {sx.min():.0f}, max {sx.max():.0f}  (manfiy ham bor — shuning uchun CV_64F)")
ko_rsat(np.abs(sx).astype(np.uint8), np.abs(sy).astype(np.uint8),
        np.clip(kuch, 0, 255).astype(np.uint8), nom="sobel.png",
        sarlavhalar=["Sobel x (vertikal chekka)", "Sobel y (gorizontal chekka)", "kuch = sqrt(x² + y²)"],
        izoh="x bo'yicha hosila tik chiziqlarni, y bo'yicha yotiq chiziqlarni ko'rsatadi.")
Chiqish
Sobel x: min -596, max 596  (manfiy ham bor — shuning uchun CV_64F)

x bo'yicha hosila tik chiziqlarni, y bo'yicha yotiq chiziqlarni ko'rsatadi.

x bo'yicha hosila tik chiziqlarni, y bo'yicha yotiq chiziqlarni ko'rsatadi.

:::gotcha CV_64F ni unutmang cv2.Sobel(img, cv2.CV_8U, 1, 0) deb yozsangiz, manfiy hosilalar nolga aylanadi — oq-dan-qora o'tish ko'rinadi, qora-dan-oq o'tish esa yo'qoladi. Chekkaning yarmi yo'qoladi va buni sezish qiyin. Har doim CV_64F (yoki CV_16S) da hisoblang, keyin np.abs va uint8 ga o'tkazing. :::

Laplacian: ikkinchi hosila

Laplacian ikki yo'nalishni birga oladi — alohida x va y kerak emas:

python9 qator
lap = cv2.Laplacian(img, cv2.CV_64F, ksize=3)
lap_u8 = np.clip(np.abs(lap), 0, 255).astype(np.uint8)
shovqinli = cv2.imread(str(RASM / "shovqinli.png"), cv2.IMREAD_GRAYSCALE)
lap_shovqin = np.clip(np.abs(cv2.Laplacian(shovqinli, cv2.CV_64F)), 0, 255).astype(np.uint8)
ko_rsat(lap_u8, lap_shovqin, nom="laplacian.png",
        sarlavhalar=["toza rasmda Laplacian", "shovqinli rasmda Laplacian"],
        izoh="Ikkinchi hosila shovqinga juda sezgir: o'ngdagi rasm deyarli butunlay 'chekka' bo'lib ketdi.")
print("chekka deb belgilangan piksellar (>40): toza",
      f"{100 * (lap_u8 > 40).mean():.1f}%", "| shovqinli", f"{100 * (lap_shovqin > 40).mean():.1f}%")
Chiqish
chekka deb belgilangan piksellar (>40): toza 1.9% | shovqinli 44.1%

Ikkinchi hosila shovqinga juda sezgir: o'ngdagi rasm deyarli butunlay 'chekka' bo'lib ketdi.

Ikkinchi hosila shovqinga juda sezgir: o'ngdagi rasm deyarli butunlay 'chekka' bo'lib ketdi.

Shuning uchun Laplacian yolg'iz kam ishlatiladi. Uning eng foydali qo'llanishi — keskinlikni o'lchash (7-bobda ishlatdik): Laplacian(...).var() katta bo'lsa rasm keskin, kichik bo'lsa xira. Avtofokus va "bu surat xiramikan?" tekshiruvi shunday ishlaydi.

Canny: amaliy standart

Canny bitta funksiya emas, besh qadamli algoritm: (1) Gauss bilan silliqlash, (2) Sobel gradienti, (3) non-maximum suppression — chekkani bir piksel qalinlikka siqish, (4) ikki chegara, (5) gisterezis — kuchsiz chekka kuchli chekkaga ulangan bo'lsagina qoldiriladi.

python8 qator
qurilish = cv2.imread(str(RASM / "qurilish_kichik.jpg"), cv2.IMREAD_GRAYSCALE)
variantlar = {}
for past, yuqori in [(50, 150), (100, 200), (150, 300)]:
    variantlar[f"{past}/{yuqori}"] = cv2.Canny(qurilish, past, yuqori)
show(pd.DataFrame([{"chegaralar": k, "chekka piksellar %": round(100 * (v > 0).mean(), 2)}
                   for k, v in variantlar.items()]))
ko_rsat(*variantlar.values(), nom="canny_chegara.png", sarlavhalar=list(variantlar),
        izoh="Chegara past bo'lsa mayda tafsilot ham chekka bo'ladi; yuqori bo'lsa faqat eng kuchli chekkalar qoladi.")
chegaralarchekka piksellar %
50/15014.95
100/20010.42
150/3007.13

Chegara past bo'lsa mayda tafsilot ham chekka bo'ladi; yuqori bo'lsa faqat eng kuchli chekkalar qoladi.

Chegara past bo'lsa mayda tafsilot ham chekka bo'ladi; yuqori bo'lsa faqat eng kuchli chekkalar qoladi.

Ikki chegara qanday tanlanadi? Amaliy qoida: yuqori chegara pastdan 2–3 barobar katta. Aniq sonlar rasmga bog'liq, shuning uchun ko'pincha medianadan hisoblanadi:

python9 qator
def avto_canny(gray, sigma=0.33):
    med = float(np.median(gray))
    past = int(max(0, (1.0 - sigma) * med))
    yuqori = int(min(255, (1.0 + sigma) * med))
    return cv2.Canny(gray, past, yuqori), past, yuqori

for nom, rasm in [("qurilish", qurilish), ("shakllar", img), ("hujjat", cv2.imread(str(RASM / "hujjat.jpg"), cv2.IMREAD_GRAYSCALE))]:
    chekka, p, y = avto_canny(rasm)
    print(f"{nom:10} median {np.median(rasm):5.0f} -> chegaralar {p:3d}/{y:3d} | chekka piksellar {100 * (chekka > 0).mean():.2f}%")
Chiqish
qurilish   median   100 -> chegaralar  67/133 | chekka piksellar 14.31%
shakllar   median   245 -> chegaralar 164/255 | chekka piksellar 0.85%
hujjat     median   195 -> chegaralar 130/255 | chekka piksellar 1.85%

Bu usul har rasm uchun o'zi moslashadi va amalda qo'lda tanlashdan ko'ra ishonchliroq.

Shovqin chekkani buzadi — avval silliqlang

python11 qator
qatorlar = []
for nom, rasm in [("shovqinli, filtrsiz", shovqinli),
                  ("shovqinli + Gauss 5x5", cv2.GaussianBlur(shovqinli, (5, 5), 0)),
                  ("shovqinli + Median 5", cv2.medianBlur(shovqinli, 5)),
                  ("toza rasm (haqiqat)", img)]:
    c = cv2.Canny(rasm, 100, 200)
    qatorlar.append({"holat": nom, "chekka piksellar %": round(100 * (c > 0).mean(), 2)})
show(pd.DataFrame(qatorlar))
ko_rsat(cv2.Canny(shovqinli, 100, 200), cv2.Canny(cv2.medianBlur(shovqinli, 5), 100, 200), cv2.Canny(img, 100, 200),
        nom="canny_shovqin.png", sarlavhalar=["filtrsiz — soxta chekkalar", "median dan keyin", "toza rasm"],
        izoh="Shovqinli rasmda Canny minglab soxta chekka topadi. Filtrdan keyin natija toza rasmnikiga yaqinlashadi.")
holatchekka piksellar %
shovqinli, filtrsiz16.72
shovqinli + Gauss 5x52.81
shovqinli + Median 50.89
toza rasm (haqiqat)0.85

Shovqinli rasmda Canny minglab soxta chekka topadi. Filtrdan keyin natija toza rasmnikiga yaqinlashadi.

Shovqinli rasmda Canny minglab soxta chekka topadi. Filtrdan keyin natija toza rasmnikiga yaqinlashadi.

Toza rasmdagi 0.85% — bizning "haqiqat"imiz. Filtrsiz Canny 16.72% topdi, ya'ni yigirma barobar ko'p: o'sha ortiqchaning deyarli hammasi shovqin. Gauss filtri uni 2.81% ga tushirdi, median esa 0.89% ga — haqiqatdan atigi 0.04 punkt farq bilan.

Bu 7-bobdagi xulosani tasdiqlaydi: shovqin turi tuz-qalampir bo'lsa, median filtr boshqalardan aniq ustun. Va bu yerda farq "chiroyliroq ko'rinadi" emas, keyingi qadam uchun hal qiluvchi: 16% chekka pikselda kontur topish mumkin emas, 0.89% da esa mumkin.

Qoida: Canny dan oldin silliqlang. Canny ichida Gauss bor, lekin u kichik; kuchli shovqinda yetmaydi.

Amaliy misol: varaqning chekkalarini topish

17-bobdagi skaner loyihasining birinchi qadami:

python8 qator
hujjat = cv2.imread(str(RASM / "hujjat.jpg"))
gray = cv2.cvtColor(hujjat, cv2.COLOR_BGR2GRAY)
silliq = cv2.GaussianBlur(gray, (5, 5), 0)
chekka = cv2.Canny(silliq, 50, 150)
yopiq = cv2.morphologyEx(chekka, cv2.MORPH_CLOSE, np.ones((5, 5), np.uint8))    # uzilgan chiziqlarni ulash
ko_rsat(chekka, yopiq, nom="hujjat_chekka.png", sarlavhalar=["Canny", "MORPH_CLOSE dan keyin"],
        izoh="Varaqning to'rt cheti aniq ko'rinadi. Keyingi qadam — shu chiziqlardan to'rtburchak yasash (10- va 17-boblar).")
print("chekka piksellar:", int((chekka > 0).sum()), "| yopilgandan keyin:", int((yopiq > 0).sum()))
Chiqish
chekka piksellar: 14775 | yopilgandan keyin: 31047

Varaqning to'rt cheti aniq ko'rinadi. Keyingi qadam — shu chiziqlardan to'rtburchak yasash (10- va 17-boblar).

Varaqning to'rt cheti aniq ko'rinadi. Keyingi qadam — shu chiziqlardan to'rtburchak yasash (10- va 17-boblar).

Xulosa

Tushuncha Asosiy fikr
Chekka Yorqinlikning keskin o'zgarishi = hosila
Sobel x va y bo'yicha alohida; CV_64F da hisoblang
Laplacian Ikkinchi hosila, shovqinga juda sezgir; keskinlik o'lchash uchun zo'r
Canny Amaliy standart: 5 qadam, ikki chegara, gisterezis
Chegara nisbati Yuqori ≈ 2–3 × past; medianadan avtomatik hisoblash mumkin
Shovqin Canny dan oldin filtrlang, aks holda minglab soxta chekka
Uzilgan chiziq MORPH_CLOSE bilan ulanadi

Talaba ishi

  1. avto_canny ning sigma sini 0.1 dan 0.6 gacha o'zgartiring. Qaysi qiymatda hujjatning to'rt cheti to'liq chiqadi va ortiqcha chiziq kam bo'ladi?
  2. Sobel ni ksize=1, 3, 5, 7 bilan sinang. Yadro kattalashganda chekka qanday o'zgaradi?
  3. cv2.Scharr ni Sobel bilan solishtiring (u 3x3 da aniqroq hisoblanadi). Farq sezilarlimi?
  4. Rasmni 90° ga burib, Sobel x va y natijalarini qayta oling. Nima kutgan edingiz va nima chiqdi?

Bu bobni bepul o'qidingiz.

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

Telegramda yozish Narxlar