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';
วิธีเรียกใช้:
php <filename> <image_path>
ตัวอย่าง:
php black_hat.php "/tmp/blackhat/1.PNG"
หมายเหตุ
- พิมพ์ "true" ถ้าพบหมวกดำและ "false" หากไม่พบ
- นี้ควรจะทำงานในรุ่นก่อนหน้าของ PHP เช่นกัน แต่เพื่อความปลอดภัยการใช้งาน PHP> = 7 กับGD
- สคริปต์นี้จริง ๆ แล้วพยายามค้นหาหมวกและโดยการทำเช่นนั้นมันอาจหมุนรูปภาพหลายครั้งและแต่ละครั้งที่ตรวจสอบพิกเซลและปมพัน ดังนั้นภาพที่มีขนาดใหญ่ขึ้นหรือมีจำนวนพิกเซลมืดกว่าสคริปต์จะใช้เวลาในการดำเนินการให้เสร็จ ควรใช้เวลาสองสามวินาทีถึงหนึ่งนาทีในการถ่ายภาพส่วนใหญ่
- ฉันชอบที่จะฝึกฝนสคริปต์นี้ให้มากขึ้น แต่ฉันไม่มีเวลาเพียงพอที่จะทำเช่นนั้น
- สคริปต์นี้ไม่ได้เล่นกอล์ฟ (อีกครั้งเพราะฉันไม่มีเวลาเพียงพอ) แต่มีศักยภาพในการเล่นกอล์ฟในกรณีที่เสมอกัน
ตัวอย่างของหมวกดำที่ตรวจพบ:

ตัวอย่างเหล่านี้ได้มาจากการวาดเส้นสีแดงบนจุดพิเศษที่พบในภาพที่สคริปต์ตัดสินใจมีหมวกสีดำ (ภาพสามารถมีการหมุนเมื่อเทียบกับภาพต้นฉบับ)
พิเศษ
ก่อนโพสต์ที่นี่ฉันทดสอบสคริปต์นี้กับอีก 15 ภาพ 10 ภาพโดยมีหมวกสีดำและ 5 ภาพโดยไม่มีหมวกสีดำและมันถูกต้องสำหรับทุกคนเช่นกัน (100%)
นี่คือไฟล์ ZIP ที่มีภาพทดสอบพิเศษที่ฉันใช้: extra.zip
ในextra/blackhatไดเรกทอรีผลการตรวจสอบที่มีเส้นสีแดงก็มีให้เช่นกัน ตัวอย่างเช่นextra/blackhat/1.pngภาพทดสอบและextra/blackhat/1_r.pngเป็นผลการตรวจสอบของมัน