Blackhat nerede?


27

Meydan okuma

Bir panelin rastgele bir xkcd çizgi romanından bir görüntüsü verildiğinde, Blackhat çizgi romandaysa ya da eğer değilse falsey ise bir gerçeği döndüren bir kod yaz.

Blackhat kim?

Blackhat , siyah şapka giyen xkcd çizgi romandaki karaktere verilen gayri resmi isimdir:

Blackhat'daki Explain xkcd sayfasından alınmıştır.

Blackhat'in şapkası her zaman düz kenarlıdır, siyahtır ve yukarıdaki resimde olduğu gibi görünür.

Diğer karakterlerde de şapka ve saç olabilir, ancak hiçbirinde siyah ve düz taraflı şapkalar olmaz.

Giriş

Görüntü STDIN aracılığıyla görüntüye veya baytlara yol olsun, istediğiniz şekilde girilebilir. Giriş olarak bir URL almanıza gerek yoktur.

kurallar

Kodlama yanıtı yasaklanmadı, ancak takdir edilmedi.

Cevap almak için internete giremezsiniz.

Örnekler

Tüm resimler https://xkcd.com adresinden çekilmiş.

Paneldeki siyah şey (dönüş truthy)


Siyah Panelde değil (dönüş falsey)


Akü Testi

Blackhat içeren 20 görüntü burada bulunabilir: https://beta-decay.github.io/blackhat.zip

Blackhat içermeyen 20 görüntü burada bulunabilir: https://beta-decay.github.io/no_blackhat.zip

Programlarınızı test etmek için daha fazla resim istiyorsanız (gizemli test durumlarını geliştirmek için), burada Blackhat'ın tüm görünümlerinin bir listesini burada bulabilirsiniz: http://www.explainxkcd.com/wiki/index.php/Category: Comics_featuring_Black_Hat

Kazanan

Blackhat'ın komik olup olmadığını doğru bir şekilde tanımlayan program çoğu görüntü için kazanır. Başlığınız, puanınızı yüzde olarak içermelidir.

Bir tiebreak durumunda, bağlı programlara "gizemli" görüntüler (yani yalnızca bildiğimler) verilecek. En doğru tanımlayan kod tiebreak kazanır.

Gizemli görüntüler skorlarla birlikte ortaya çıkacak.

Not: Görünüşe göre Randall'ın onun için adı Hat Guy olabilir. Ben olsa Blackhat'ı tercih ederim.


12
Mathematica’da bunun için bir yerleşik varsa, hiç şaşırmam. ( Başvuru için )
J. Sallé

5
Farklı bir kravat kırıcı için öneri: burada ortaya çıkmamış, farklı, daha küçük bir görüntü seti (5 gerçek durum ve 5 yanlış) diyelim ve kravat kırıcının kazananı bu bilinmeyen görüntülere en iyi şekilde genel olandır. Bu, bu belirli görüntülere uyan çözümlere karşı daha genel akıllı çözümleri teşvik edecektir.
sundar - Reinstate Monica,

3
Polis ve RIAA / MPAA ile yapılan test davaları çok kötü. İyi test bataryası, @ BetaDecay.
sundar - Reinstate Monica,


1
@ Night2 Üzgünüz! Sadece herhangi birisini kravat yapmayı planladım. % 100 üzerinde güzel bir iş olsa!
Beta Ayı

Yanıtlar:


16

PHP (> = 7),% 100 (40/40)

<?php

set_time_limit(0);

class BlackHat
{
    const ROTATION_RANGE = 45;

    private $image;
    private $currentImage;
    private $currentImageWidth;
    private $currentImageHeight;

    public function __construct($path)
    {
        $this->image = imagecreatefrompng($path);
    }

    public function hasBlackHat()
    {
        $angles = [0];

        for ($i = 1; $i <= self::ROTATION_RANGE; $i++) {
            $angles[] = $i;
            $angles[] = -$i;
        }

        foreach ($angles as $angle) {
            if ($angle == 0) {
                $this->currentImage = $this->image;
            } else {
                $this->currentImage = $this->rotate($angle);
            }

            $this->currentImageWidth = imagesx($this->currentImage);
            $this->currentImageHeight = imagesy($this->currentImage);

            if ($this->findBlackHat()) return true;
        }

        return false;
    }

    private function findBlackHat()
    {
        for ($y = 0; $y < $this->currentImageHeight; $y++) {
            for ($x = 0; $x < $this->currentImageWidth; $x++) {
                if ($this->isBlackish($x, $y) && $this->isHat($x, $y)) return true;
            }
        }

        return false;
    }

    private function isHat($x, $y)
    {
        $hatWidth = $this->getBlackishSequenceSize($x, $y, 'right');
        if ($hatWidth < 10) return false;

        $hatHeight = $this->getBlackishSequenceSize($x, $y, 'bottom');

        $hatLeftRim = $hatRightRim = 0;
        for (; ; $hatHeight--) {
            if ($hatHeight < 5) return false;

            $hatLeftRim = $this->getBlackishSequenceSize($x, $y + $hatHeight, 'left');
            if ($hatLeftRim < 3) continue;

            $hatRightRim = $this->getBlackishSequenceSize($x + $hatWidth, $y + $hatHeight, 'right');
            if ($hatRightRim < 2) $hatRightRim = $this->getBlackishSequenceSize($x + $hatWidth, $y + $hatHeight, 'right', 'isLessBlackish');
            if ($hatRightRim < 2) continue;

            break;
        }

        $ratio = $hatWidth / $hatHeight;
        if ($ratio < 2 || $ratio > 4.2) return false;

        $widthRatio = $hatWidth / ($hatLeftRim + $hatRightRim);
        if ($widthRatio < 0.83) return false;
        if ($hatHeight / $hatLeftRim < 1 || $hatHeight / $hatRightRim < 1) return false;

        $pointsScore = 0;
        if ($this->isSurroundedBy($x, $y, 3, true, true, false, false)) $pointsScore++;
        if ($this->isSurroundedBy($x + $hatWidth, $y, 3, true, false, false, true)) $pointsScore++;
        if ($this->isSurroundedBy($x, $y + $hatHeight, 3, false, false, true, false)) $pointsScore++;
        if ($this->isSurroundedBy($x + $hatWidth, $y + $hatHeight, 3, false, false, true, false)) $pointsScore++;
        if ($this->isSurroundedBy($x - $hatLeftRim, $y + $hatHeight, 3, true, true, true, false)) $pointsScore++;
        if ($this->isSurroundedBy($x + $hatWidth + $hatRightRim, $y + $hatHeight, 3, true, false, true, true)) $pointsScore++;
        if ($pointsScore < 3 || ($hatHeight >= 19 && $pointsScore < 4) || ($hatHeight >= 28 && $pointsScore < 5)) return false;

        $middleCheckSize = ($hatHeight >= 15 ? 3 : 2);
        if (!$this->isSurroundedBy($x + (int)($hatWidth / 2), $y, $middleCheckSize, true, null, null, null)) return false;
        if (!$this->isSurroundedBy($x + (int)($hatWidth / 2), $y + $hatHeight, $middleCheckSize, null, null, true, null)) {
            if (!$this->isSurroundedBy($x + (int)(($hatWidth / 4) * 3), $y + $hatHeight, $middleCheckSize, null, null, true, null)) return false;
        }
        if (!$this->isSurroundedBy($x, $y + (int)($hatHeight / 2), $middleCheckSize + 1, null, true, null, null)) return false;
        if (!$this->isSurroundedBy($x + $hatWidth, $y + (int)($hatHeight / 2), $middleCheckSize, null, null, null, true)) return false;

        $badBlacks = 0;
        for ($i = 1; $i <= 3; $i++) {
            if ($y - $i >= 0) {
                if ($this->isBlackish($x, $y - $i)) $badBlacks++;
            }

            if ($x - $i >= 0 && $y - $i >= 0) {
                if ($this->isBlackish($x - $i, $y - $i)) $badBlacks++;
            }
        }
        if ($badBlacks > 2) return false;

        $total = ($hatWidth + 1) * ($hatHeight + 1);
        $blacks = 0;
        for ($i = $x; $i <= $x + $hatWidth; $i++) {
            for ($j = $y; $j <= $y + $hatHeight; $j++) {
                $isBlack = $this->isBlackish($i, $j);
                if ($isBlack) $blacks++;
            }
        }

        if (($total / $blacks > 1.15)) return false;

        return true;
    }

    private function getColor($x, $y)
    {
        return imagecolorsforindex($this->currentImage, imagecolorat($this->currentImage, $x, $y));
    }

    private function isBlackish($x, $y)
    {
        $color = $this->getColor($x, $y);
        return ($color['red'] < 78 && $color['green'] < 78 && $color['blue'] < 78 && $color['alpha'] < 30);
    }

    private function isLessBlackish($x, $y)
    {
        $color = $this->getColor($x, $y);
        return ($color['red'] < 96 && $color['green'] < 96 && $color['blue'] < 96 && $color['alpha'] < 40);
    }

    private function getBlackishSequenceSize($x, $y, $direction, $fn = 'isBlackish')
    {
        $size = 0;

        if ($direction == 'right') {
            for ($x++; ; $x++) {
                if ($x >= $this->currentImageWidth) break;
                if (!$this->$fn($x, $y)) break;
                $size++;
            }
        } elseif ($direction == 'left') {
            for ($x--; ; $x--) {
                if ($x < 0) break;
                if (!$this->$fn($x, $y)) break;
                $size++;
            }
        } elseif ($direction == 'bottom') {
            for ($y++; ; $y++) {
                if ($y >= $this->currentImageHeight) break;
                if (!$this->$fn($x, $y)) break;
                $size++;
            }
        }

        return $size;
    }

    private function isSurroundedBy($x, $y, $size, $top = null, $left = null, $bottom = null, $right = null)
    {
        if ($top !== null) {
            $flag = false;
            for ($i = 1; $i <= $size; $i++) {
                if ($y - $i < 0) break;
                $isBlackish = $this->isBlackish($x, $y - $i);

                if (
                    ($top && !$isBlackish) ||
                    (!$top && $isBlackish)
                ) {
                    $flag = true;
                } elseif ($flag) {
                    return false;
                }
            }
            if (!$flag) return false;
        }

        if ($left !== null) {
            $flag = false;
            for ($i = 1; $i <= $size; $i++) {
                if ($x - $i < 0) break;
                $isBlackish = $this->isBlackish($x - $i, $y);

                if (
                    ($left && !$isBlackish) ||
                    (!$left && $isBlackish)
                ) {
                    $flag = true;
                } elseif ($flag) {
                    return false;
                }
            }
            if (!$flag) return false;
        }

        if ($bottom !== null) {
            $flag = false;
            for ($i = 1; $i <= $size; $i++) {
                if ($y + $i >= $this->currentImageHeight) break;
                $isBlackish = $this->isBlackish($x, $y + $i);

                if (
                    ($bottom && !$isBlackish) ||
                    (!$bottom && $isBlackish)
                ) {
                    $flag = true;
                } elseif ($flag) {
                    return false;
                }
            }
            if (!$flag) return false;
        }

        if ($right !== null) {
            $flag = false;
            for ($i = 1; $i <= $size; $i++) {
                if ($x + $i >= $this->currentImageWidth) break;
                $isBlackish = $this->isBlackish($x + $i, $y);

                if (
                    ($right && !$isBlackish) ||
                    (!$right && $isBlackish)
                ) {
                    $flag = true;
                } elseif ($flag) {
                    return false;
                }
            }
            if (!$flag) return false;
        }

        return true;
    }

    private function rotate($angle)
    {
        return imagerotate($this->image, $angle, imagecolorallocate($this->image, 255, 255, 255));
    }
}

$bh = new BlackHat($argv[1]);
echo $bh->hasBlackHat() ? 'true' : 'false';

Çalıştırmak için:

php <filename> <image_path>

Örnek:

php black_hat.php "/tmp/blackhat/1.PNG"

notlar

  • Siyah şapka bulursa "true", bulamazsa "false" yazar.
  • Bu PHP'nin önceki sürümlerinde de çalışmalı, ancak güvenli olması için GD ile PHP> = 7 kullanmalısınız .
  • Bu senaryo aslında şapkayı bulmaya çalışır ve bunu yaparak görüntüyü birçok kez döndürebilir ve her seferinde binlerce ve binlerce piksel ve ipucunu kontrol eder. Bu yüzden, görüntü ne kadar büyük olursa veya sahip olduğu daha karanlık pikseller için, komut dosyasının tamamlanması daha uzun sürer. Yine de görüntülerin çoğunluğu için birkaç dakika ile bir dakika arasında sürebilir.
  • Bu senaryoyu daha fazla eğitmeyi çok isterdim, ancak yapacak vaktim yok.
  • Bu senaryo golf oynamıyor (yine de yeterli zamanım olmadığından), ancak beraberlik durumunda golf oynama potansiyeli çok fazla.

Tespit edilen siyah şapkalardan bazı örnekler:

görüntü tanımını buraya girin

Bu örnekler, betiğin siyah bir şapkaya sahip olduğuna karar verilen görüntünün üzerinde bulunan özel noktalara kırmızı çizgiler çizerek elde edilir (görüntüler orijinal olanlara göre dönebilir).


Ekstra

Buraya yazmadan önce, bu senaryoyu, 10'u siyah şapkalı ve 5'i siyah şapkalı olmayan 15 resimden oluşan bir gruba karşı test ettim ve hepsi için de doğru gitti (% 100).

Kullandığım ekstra test resimlerini içeren ZIP dosyası:

Olarak extra/blackhatdizin kırmızı çizgi ile tespit sonuçları da mevcuttur. Örneğin extra/blackhat/1.png, test görüntüsüdür ve extra/blackhat/1_r.pngbunun tespit sonucudur.


Tiebreak kod golf değil. Bunun yerine, programlar, bağlantı kopması çözülene kadar gizli test durumları ile beslenir. Sonra size sonucu söyleyeceğim ve test vakalarını göndereceğim :)
Beta Decay

1
@BetaDecay: Açıklığa kavuşturduğun için teşekkürler, bu cümle (beraberinde en kısa kazanan) sorunun önceki sürümlerinden kafamdaydı, bu yüzden gizli test durumlarında bir bağ olursa en kısa kodun kazanacağını düşünüyordum. Benim hatam!
Gece 2

7
Sen :) çok az olasılıkla görüntü işleme dili için ödülü kazanmak
Anush

@Anush Eh, en azından PHP imagerotateyerleşik, bu yüzden ...
user202729

PHP ile ilgili sevdiğim şey, neredeyse her şey için bazı temel işlevlere sahip olmasıdır. GD'yi yıllardır bir araya getirdi ve GD aslında görüntülerle çalışmanın en yaygın gereksinimlerini karşılar. Fakat PHP hakkında daha çok sevdiğim şey, her zaman size daha fazla verebilecek bazı uzantılar / paketler olduğudur (büyük bir topluluğa sahip olmaktan dolayı). Örneğin , gerçek görüntü işlemenin yapılmasını sağlayan PHP için OpenCV eklentileri var !
Gece2

8

Matlab,% 87,5

function hat=is_blackhat_here2(filepath)

img_hsv = rgb2hsv(imread(filepath));
img_v = img_hsv(:,:,3);

bw = imdilate(imerode( ~im2bw(img_v), strel('disk', 4, 8)), strel('disk', 4, 8));
bw = bwlabel(bw, 8);
bw = imdilate(imerode(bw, strel('disk', 1, 4)), strel('disk', 1, 4));
bw = bwlabel(bw, 4);

region_stats = regionprops(logical(bw), 'all');
hat = false;
for i = 1 : numel(region_stats)
    if mean(img_v(region_stats(i).PixelIdxList)) < 0.15 ...
            && region_stats(i).Area > 30 ...
            && region_stats(i).Solidity > 0.88 ...
            && region_stats(i).Eccentricity > 0.6 ...
            && region_stats(i).Eccentricity < 1 ...
            && abs(region_stats(i).Orientation) < 75...
            && region_stats(i).MinorAxisLength / region_stats(i).MajorAxisLength < 0.5;
        hat = true;
        break;
    end
end

Aday bölgelerin şekline bazı kontroller eklenerek önceki sürümün geliştirilmesi.

HAT setinde sınıflandırma hataları : 4, 14, 15, 17 numaralı görüntüler .

HONATSIZ HAT setinde sınıflandırma hataları : görüntüler 4 .

Düzeltilmiş sınıflandırılmış görüntülerin bazı örnekleri: görüntü tanımını buraya girin görüntü tanımını buraya girin

Yanlış sınıflandırılmış görüntü örneği:

görüntü tanımını buraya girin

ESKİ SÜRÜM (% 77,5)

function hat=is_blackhat_here(filepath)

img_hsv = rgb2hsv(imread(filepath));
img_v = img_hsv(:,:,3);
bw = imerode(~im2bw(img_v), strel('disk', 5, 8));

hat =  mean(img_v(bw)) < 0.04;

Mnemonic'in önerdiği çözüme benzer, ancak HSV görüntüsünün V kanalını temel alan görüntü erozyonuna dayanan bir yaklaşım. Ayrıca, seçilen alanın kanalının ortalama değeri kontrol edilir (büyüklüğü değil).

HAT setinde sınıflandırma hataları : 4, 5, 10 numaralı görüntüler .

HAT HAT kümesinde sınıflandırma hataları : 4, 5, 6, 7, 13, 14 numaralı görüntüler .


7

Pyth ,% 62,5

<214.O.n'z

Stdin'deki bir görüntü dosyasının dosya adını kabul eder. TrueTüm RGB renk bileşenlerinin ortalaması 214'ten büyükse döndürür . Doğru okudunuz: görünüşe göre siyah olan görüntüler siyah olmayan görüntülerden daha parlak olma eğilimindedir.

(Kesinlikle birileri daha iyisini yapabilir; bu değil !)


2
Anladığım kadar Pyth'in gücüne hayran kaldım: D
Beta Decay, 19

Bir an için ben "Pyth bir siyah şapkalı Görüntüleri tanımakta inşa etti ne zamandan beri" düşünce
Luis Felipe De isa Munoz

2
Σben=2540(40ben)2407.7%

6

Python 2, % 65,% 72,5,% 77,5 (= 31/40)

import cv2
import numpy as np
from scipy import misc

def blackhat(path):
    im = misc.imread(path)
    black = (im[:, :, 0] < 10) & (im[:, :, 1] < 10) & (im[:, :, 2] < 10)
    black = black.astype(np.ubyte)

    black = cv2.erode(black, np.ones((3, 3)), iterations=3)

    return 5 < np.sum(black) < 2000

Bu, hangi piksellerin siyah olduğunu belirler, daha sonra küçük bitişik parçaları aşındırır. Kesinlikle burada iyileştirme için yer var.

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.