Upgoat или Downgoat?

309

Учитывая изображение козла, ваша программа должна попытаться определить, перевернутый козел или нет.

Примеры

Это примеры того, что может быть входом. Не фактические входы

Входные данные:

Downgoat

Выход: Downgoat

спекуляция

Ваша программа должна быть не более 30 000 байтов

  • На входе будет полный козел
  • Картина всегда будет содержать козу
  • Если коза перевернута, выведите Downgoat, иначеUpgoat

Ввод будет, однако, вы можете взять изображение в качестве ввода (имя файла, base64 изображения и т. Д.)

Не полагайтесь на имя изображения или другие метаданные, содержащие «Upgoat» или «Downgoat», поскольку имена файлов gist приведены только для справки.


Пожалуйста, не используйте жесткий код . Это скучно, я не могу навязать это полностью, но могу спросить.

Тестовые случаи

Суть с изображениями . изображения , начиная с downgoatесть Downgoatвыход и изображения , начиная с upgoatесть Upgoatвыход.

Вторая партия тестовых случаев Обязательно протестируйте свои изображения во всех тестовых случаях. Эти изображения jpgс. Размеры изображений действительно изменяются , но не что много.


Примечание. Перед принятием ответа можно добавить несколько тестовых примеров, чтобы избежать жестких кодов ответов и проверить общую производительность программы.

Бонусные баллы за правильный аватар: P

счет

Оценка - это процент, который можно рассчитать по формуле: (number_correct / total) * 100

Downgoat
источник
1
Считается ли «примерка» жестким кодированием?
Ник Т
@NickT, что ты имеешь в виду под "примеркой"?
Вниз
@ Downgoat - параметры для модели (уравнения), которые выводятся, если козел стоит в правильном направлении. Под « подгонкой» я подразумеваю подгонку модели ко всему набору данных, а не к некоторому обучающему набору.
Ник Т
29
Мне любопытно посмотреть, как эти решения будут обрабатывать двух коз на одной картине.
Даниил

Ответы:

293

Mathematica, 100%, 141 байт

f@x_:=Count[1>0]@Table[ImageInstanceQ[x,"caprine animal",RecognitionThreshold->i/100],{i,0,50}];If[f@#>f@ImageReflect@#,"Up","Down"]<>"goat"&

Ну, это больше похоже на обман. Это также невероятно медленно и очень глупо. Функция fпримерно показывает, насколько высоко вы можете установить порог распознавания в одном из встроенных в компьютерное зрение Mathematica изображений, и при этом распознавать изображение как животное-каприн.

Затем мы видим, является ли изображение или перевернутое изображение более козлиным. Работает над изображением вашего профиля только потому, что галстук нарушен в пользу понижения. Вероятно, существует множество способов, которыми это можно улучшить, включая вопрос о том, представляет ли изображение Bovids или другие обобщения типа сущностей животных-капринов.

Ответьте в виде письменных оценок 100% для первого набора тестирования и 94% для второго набора тестирования, поскольку алгоритм дает неубедительный результат для козы 1. Это может быть повышено до 100% за счет еще более длительного вычислительного времени: тестирование больше значений RecognitionThreshold. Повышение от 100до 1000достаточности; по какой-то причине Mathematica считает, что это очень плохой образ! Изменение объекта распознавания с животного-каприна на копытного млекопитающего также, кажется, работает.

Ungolfed:

goatness[image_] := Count[
                      Table[
                        ImageInstanceQ[
                          image, Entity["Concept", "CaprineAnimal::4p79r"],
                          RecognitionThreshold -> threshold
                        ],
                        {threshold, 0, 0.5, 0.01}
                      ],
                      True
                    ]

Function[{image},
  StringJoin[      
    If[goatness[image] > goatness[ImageReflect[image]],
      "Up",
      "Down"
    ],
    "goat"
  ]
]

Альтернативное решение, 100% + бонус

g[t_][i_] := ImageInstanceQ[i, "caprine animal", RecognitionThreshold -> t]
f[i_, l_: 0, u_: 1] := Module[{m = (2 l + u)/3, r},
  r = g[m] /@ {i, ImageReflect@i};
  If[Equal @@ r,
   If[First@r, f[i, m, u], f[i, l, m]],
   If[First@r, "Up", "Down"] <> "goat"
   ]
  ]

Этот использует ту же стратегию, что и раньше, но с бинарным поиском через порог. Здесь задействованы две функции:

  • g[t]возвращает, является ли его аргумент козлиным изображением с порогом t.
  • fпринимает три параметра: изображение и верхнюю и нижнюю границу порога. Это рекурсивно; это работает, проверяя порог mмежду верхним и нижним порогами (смещенный к нижнему). Если изображение и отраженное изображение являются козлиными или не козлиными, оно удаляет нижнюю или верхнюю часть диапазона в зависимости от ситуации и вызывает себя снова. В противном случае, если одно изображение является козлиным, а другое - не козлиным, оно возвращается, Upgoatесли первое изображение является козьим, а в Downgoatпротивном случае (если второе, отраженное изображение является козлиным).

Определения функций заслуживают небольшого пояснения. Во-первых, применение функции левоассоциативно. Это означает, что нечто подобное g[x][y]интерпретируется как (g[x])[y]; «Результат g[x]применения к y

Во-вторых, назначение в Mathematica примерно эквивалентно определению правила замены. То есть, f[x_] := x^2это не значит «объявить функцию с именем fс параметром , xкоторый возвращает x^2;» его значение ближе к: «всякий раз, когда вы видите что-то подобное f[ ... ], называйте вещь внутри xи заменяйте все на x^2».

Соединяя эти два значения вместе, мы можем видеть, что определение gговорит Mathematica заменить любое выражение формы (g[ ... ])[ ... ]правой частью присваивания.

Когда Mathematica встречает выражение g[m](во второй строке f), оно видит, что выражение не соответствует ни одному из известных ему правил, и оставляет его без изменений. Затем он соответствует Mapоператору /@, чьи аргументы g[m]и список {i, ImageReflect@i}. ( /@это инфиксная запись; это выражение в точности эквивалентно Map[g[m], { ... }].) MapЗаменяется путем применения его первого аргумента к каждому элементу его второго аргумента, поэтому мы получаем {(g[m])[i], (g[m])[ ... ]}. Теперь Mathematica видит, что каждый элемент соответствует определению gи выполняет замену.

Таким образом, мы gдолжны действовать как функция, которая возвращает другую функцию; то есть он действует примерно так, как мы написали:

g[t_] := Function[{i}, ImageInstanceQ[i, "caprine animal", RecognitionThreshold -> t]]

(За исключением того, что в этом случае само g[t]по себе оценивается как a Function, тогда как раньше само g[t]по себе не было преобразовано вообще.)

Последний трюк, который я использую - это необязательный шаблон. Шаблон l_ : 0означает «сопоставить любое выражение и сделать его доступным как l, или ничего не сопоставить и сделать 0доступным как l». Итак, если вы вызываете f[i]с одним аргументом (проверяемое изображение), это как если бы вы звонили f[i, 0, 1].

Вот тестовый жгут, который я использовал:

gist = Import["https://api.github.com/gists/3fb94bfaa7364ccdd8e2", "JSON"];
{names, urls} = Transpose[{"filename", "raw_url"} /. Last /@ ("files" /. gist)];
images = Import /@ urls;
result = f /@ images
Tally@MapThread[StringContainsQ[##, IgnoreCase -> True] &, {names, result}]
(* {{True, 18}} *)

user = "items" /.
           Import["https://api.stackexchange.com/2.2/users/40695?site=codegolf", "JSON"];
pic = Import[First["profile_image" /. user]];
name = First["display_name" /. user];
name == f@pic
(* True *)
Симмонс
источник
344
Mathematica имеет встроенную функцию определения коз. Я не знаю, как к этому относиться.
Роберт Фрейзер
119
Whaaat Oo есть встроенный для этого .... Wow ...
Downgoat
171
Ты козел, что шутишь ...
CorsiKa
27
+1 за то, что Mathematica может видеть, какое изображение «более козлиное».
QBrute
9
Это положительно смешно. +1.
Приближается к
71

JavaScript, 93,9%

var solution = function(imageUrl, settings) {

  // Settings
  settings = settings || {};
  var colourDifferenceCutoff = settings.colourDifferenceCutoff || 0.1,
      startX = settings.startX || 55,
      startY = settings.startY || 53;

  // Draw the image to the canvas
  var canvas = document.createElement("canvas"),
      context = canvas.getContext("2d"),
      image = new Image();
  image.src = imageUrl;
  image.onload = function(e) {
    canvas.width = image.width;
    canvas.height = image.height;
    context.drawImage(image, 0, 0);

    // Gets the average colour of an area
    function getColour(x, y) {

      // Get the image data from the canvas
      var sizeX = image.width / 100,
          sizeY = image.height / 100,
          data = context.getImageData(
            x * sizeX | 0,
            y * sizeY | 0,
            sizeX | 0,
            sizeY | 0
          ).data;

      // Get the average of the pixel colours
      var average = [ 0, 0, 0 ],
          length = data.length / 4;
      for(var i = 0; i < length; i++) {
        average[0] += data[i * 4] / length;
        average[1] += data[i * 4 + 1] / length;
        average[2] += data[i * 4 + 2] / length;
      }
      return average;
    }

    // Gets the lightness of similar colours above or below the centre
    function getLightness(direction) {
      var centre = getColour(startX, startY),
          colours = [],
          increment = direction == "above" ? -1 : 1;
      for(var y = startY; y > 0 && y < 100; y += increment) {
        var colour = getColour(startX, y);

        // If the colour is sufficiently different
        if(
          (
            Math.abs(colour[0] - centre[0]) +
            Math.abs(colour[1] - centre[1]) +
            Math.abs(colour[2] - centre[2])
          ) / 256 / 3
          > colourDifferenceCutoff
        ) break;
        else colours.push(colour);
      }

      // Calculate the average lightness
      var lightness = 0;
      for(var i = 0; i < colours.length; i++) {
        lightness +=
          (colours[i][0] + colours[i][1] + colours[i][2])
          / 256 / 3 / colours.length;
      }

      /*
      console.log(
        "Direction:", direction,
        "Checked y = 50 to:", y,
        "Average lightness:", lightness
      );
      */
      return lightness;
    }

    // Compare the lightness above and below the starting point
    //console.log("Results for:", imageUrl);
    var above = getLightness("above"),
        below = getLightness("below"),
        result = above > below ? "Upgoat" : "Downgoat";
    console.log(result);
    return result;
  };
};
<div ondrop="event.preventDefault();r=new FileReader;r.onload=e=>{document.getElementById`G`.src=imageUrl=e.target.result;console.log=v=>document.getElementById`R`.textContent=v;solution(imageUrl);};r.readAsDataURL(event.dataTransfer.files[0]);" ondragover="event.preventDefault()" style="height:160px;border-radius:12px;border:2px dashed #999;font-family:Arial,sans-serif;padding:8px"><p style="font-style:italic;padding:0;margin:0">Drag & drop image <strong>file</strong> (not just link) to test here... (requires HTML5 browser)</p><image style="height:100px" id="G" /><pre id="R"></pre></div>

объяснение

Простая реализация идеи @BlackCap по проверке источника света.

Большинство коз находится в центре их изображений, а их животы всегда темнее спины из-за солнечного света. Программа запускается в середине изображения и запоминает цвет. Затем он получает среднюю яркость пикселей выше и ниже центра до того места, где цвет отличается от цвета в центре (когда тело козла заканчивается и начинается фон). Независимо от того, какая сторона светлее, определяется, является ли она нижней или нижней.

Сбои для отрицательной 9 и 7 и 9 во втором контрольном примере.

user81655
источник
4
Приятно! Я не ожидал, что 100% будет таким легким. Я добавил вторую партию тестовых случаев. Можете ли вы обновить свой ответ на основании этого?
Вниз
Вот альтернативная ссылка, это работает?
Downgoat
@ Downgoat Да. Оценка обновлена.
user81655
К сожалению, это не удается после того, как я повернул изображение на 180 ° и перевернул его вертикально. Скриншот
mr5
@ mr5 Интересно ... Значит, изображение на скриншоте немного отличается от приглушенного 4? Также есть небольшие различия между браузерами (и, возможно, операционными системами?). С параметрами в этом ответе я получил те же результаты для Chrome и Firefox (используя Windows).
user81655
63

Python, 100%, 225 байт

import requests

SEARCH = "http://www.bing.com/images/searchbyimage?FORM=IRSBIQ&cbir=sbi&imgurl="
THRESHOLD = 30
url = raw_input()
print "Upgoat" if requests.get(SEARCH + url).content.count('img') > THRESHOLD else "Downgoat"

Используйте обратный поиск изображений на козе. Если страница возвращает удовлетворительное количество результатов, это, вероятно, козел вверх. Это решение, вероятно, не будет работать на нарисованных от руки козлах или если Bing когда-либо будет поврежден.

jasonshao
источник
32
Я не уверен, что я чувствую по поводу этого ответа. Это граница действительна и почти нарушает эту лазейку . В настоящее время нарушается явное правило , согласно которому входные данные являются либо файлом, либо локальным путем, а не URL-адресом. Это интересный ответ, но, учитывая, насколько он действителен на границе, я бы сказал, что его конкурентоспособность сомнительна.
Вниз
50
@ Downgoat, так что ты отклонил его ответ?
Аве
2
исправить это, загрузив файл в imgur или что-то в этом роде ^^ И почему в мире вы бы использовали bing ???
Eumel
17
@Eumel Потому что Google проверяет, принадлежит ли пользовательский агент в HTTP-запросе реальному веб-браузеру (или тому, что они разрешают), а не какому-либо другому приложению или сценарию. Бинг не проверяет это, они отчаянно нуждаются в получении входящих запросов. Я думаю, что User-Agent может быть подделан с дополнительным кодом, и это не имеет значения, так как это не code-golf.
ДжордиВилаплана,
14
Эта стандартная лазейка предназначена для кодовых гольф-ответов, чтобы сделать их меньше. Это не соревнование в гольф-коде, поэтому я не понимаю, почему бы применить эту лазейку
SztupY
58

Ява, 93,9% 100%

Это работает путем определения контрастности строк в верхней и нижней части изображения. Я предполагаю, что контраст в нижней половине изображения больше по двум причинам:

  • 4 ножки находятся в нижней части
  • фон в верхней части будет размытым, потому что обычно он не в фокусе

Я определяю контраст для каждой строки, вычисляя разницу значений соседних пикселей, возводя в квадрат разницу и суммируя все квадраты.

Обновить

Некоторые изображения из второй партии вызвали проблемы с оригинальным алгоритмом.

upgoat3.jpg

Это изображение использовало прозрачность, которая была проигнорирована ранее. Есть несколько возможностей решить эту проблему, но я просто выбрал рендеринг всех изображений на черном фоне размером 400x400. Это имеет следующие преимущества:

  • обрабатывает изображения с альфа-каналом
  • обрабатывает индексированные и полутоновые изображения
  • повышает производительность (нет необходимости обрабатывать эти 13MP изображения)

downgoat8.jpg / upgoat8.jpg

Эти изображения имеют преувеличенные детали в теле козла. Решением здесь было размытие изображения только в вертикальном направлении. Однако это породило проблемы с изображениями из первого пакета, которые имеют вертикальные структуры на заднем плане. Решение здесь состояло в том, чтобы просто считать различия, которые превышают определенный порог, и игнорировать фактическое значение разницы.

Вкратце, обновленный алгоритм ищет области с множеством различий в изображениях, которые после предварительной обработки выглядят так:

введите описание изображения здесь

import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.awt.image.Raster;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

public class UpDownGoat {
    private static final int IMAGE_SIZE = 400;
    private static final int BLUR_SIZE = 50;

    private static BufferedImage blur(BufferedImage image) {
        BufferedImage result = new BufferedImage(image.getWidth(), image.getHeight() - BLUR_SIZE + 1,
                BufferedImage.TYPE_INT_RGB);
        for (int b = 0; b < image.getRaster().getNumBands(); ++b) {
            for (int x = 0; x < result.getWidth(); ++x) {
                for (int y = 0; y < result.getHeight(); ++y) {
                    int sum = 0;
                    for (int y1 = 0; y1 < BLUR_SIZE; ++y1) {
                        sum += image.getRaster().getSample(x, y + y1, b);
                    }
                    result.getRaster().setSample(x, y, b, sum / BLUR_SIZE);
                }
            }
        }
        return result;
    }

    private static long calcContrast(Raster raster, int y0, int y1) {
        long result = 0;
        for (int b = 0; b < raster.getNumBands(); ++b) {
            for (int y = y0; y < y1; ++y) {
                long prev = raster.getSample(0, y, b);
                for (int x = 1; x < raster.getWidth(); ++x) {
                    long current = raster.getSample(x, y, b);
                    result += Math.abs(current - prev) > 5 ? 1 : 0;
                    prev = current;
                }
            }
        }
        return result;
    }

    private static boolean isUp(File file) throws IOException {
        BufferedImage image = new BufferedImage(IMAGE_SIZE, IMAGE_SIZE, BufferedImage.TYPE_INT_RGB);
        Graphics2D graphics = image.createGraphics();
        graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
        graphics.drawImage(ImageIO.read(file), 0, 0, image.getWidth(), image.getHeight(), null);
        graphics.dispose();
        image = blur(image);
        int halfHeight = image.getHeight() / 2;
        return calcContrast(image.getRaster(), 0, halfHeight) < calcContrast(image.getRaster(),
                image.getHeight() - halfHeight, image.getHeight());
    }

    public static void main(String[] args) throws IOException {
        System.out.println(isUp(new File(args[0])) ? "Upgoat" : "Downgoat");
    }
}
Sleafar
источник
Вот альтернативная ссылка, это работает?
Downgoat
@ Downgoat Да, это сработало. Я обновил счет (не считая бонусных баллов за ваш аватар, который распознается правильно :).
Sleafar
38

Python 3, 91,6%

отредактированный с новыми тестами

установите имя файла к изображению козы, которое вы хотите проверить. Он использует ядро, чтобы сделать изображение сверху / снизу асимметричным. Я попробовал оператор sobel, но это было лучше.

from PIL import Image, ImageFilter
import statistics
k=(2,2,2,0,0,0,-2,-2,-2)
filename='0.png'
im=Image.open(filename)
im=im.filter(ImageFilter.Kernel((3,3),k,1,128))
A=list(im.resize((10,10),1).getdata())
im.close()
a0=[]
aa=0
for y in range(0,len(A)):
    y=A[y]
    a0.append(y[0]+y[1]+y[2])
aa=statistics.mean(a0)
if aa<383.6974:
    print('Upgoat')
else:
    print('Downgoat')
фуксин
источник
3
+1 Отличная работа! Я действительно должен выяснить, как установить PIL на Mac ...
Downgoat
Я добавил вторую партию тестовых случаев. Можете ли вы обновить свой ответ на основании этого?
Вниз
@ Downgoat только что сделал
пурпурный
@Downgoatpip install Pillow
Ассаф Лави
16

OpenCV с Hough Transform, 100%

Моя первоначальная идея состояла в том, чтобы обнаружить вертикальные линии ног козла и определить его вертикальное положение относительно тела и горизонта.

Как выясняется, на всех изображениях земля чрезвычайно шумная, что приводит к большому количеству выходных данных обнаружения края Канни и соответствующих обнаруженных линий из преобразования Хафа. Тогда моей стратегией было определить, лежат ли горизонтальные линии в верхней или нижней половине изображения, что было достаточно для решения проблемы.

# Most of this code is from OpenCV examples
import cv2
import numpy as np

def is_upgoat(path):
    img = cv2.imread(path)
    height, width, channels = img.shape
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    edges = cv2.Canny(gray, 100, 200, apertureSize=3)

    lines = cv2.HoughLines(edges, 1, np.pi/180, 200, None, 0, 0, np.pi/2-0.5, np.pi/2+0.5)
    rho_small = 0

    for line in lines:
        rho, theta = line[0]
        a = np.cos(theta)
        b = np.sin(theta)
        x0 = a*rho
        y0 = b*rho
        x1 = int(x0 + 5000*(-b))
        y1 = int(y0 + 5000*(a))
        x2 = int(x0 - 5000*(-b))
        y2 = int(y0 - 5000*(a))

        if rho/height < 1/2: rho_small += 1
        cv2.line(img,(x1,y1),(x2,y2),(0,0,255),1, cv2.LINE_AA)

    output_dir = "output/"
    img_name = path[:-4]
    cv2.imwrite(output_dir + img_name + "img.jpg", img)
    cv2.imwrite(output_dir + img_name + "edges.jpg", edges)

    return rho_small / len(lines) < 1/2


for i in range(1, 10):
    downgoat_path = "downgoat" + str(i) + ".jpg"
    print(downgoat_path, is_upgoat(downgoat_path))

for i in range(1, 10):
    upgoat_path = "upgoat" + str(i) + ".jpg"
    print(upgoat_path, is_upgoat(upgoat_path))

Вот вся функция без вывода изображений:

def is_upgoat(path):
    img = cv2.imread(path)
    height, width, channels = img.shape
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    edges = cv2.Canny(gray, 100, 200, apertureSize=3)

    lines = cv2.HoughLines(edges, 1, np.pi/180, 200, None, 0, 0, np.pi/2-0.5, np.pi/2+0.5)
    rho_small = 0

    for line in lines:
        rho, theta = line[0]
        if rho/height < 1/2: rho_small += 1

    return rho_small / len(lines) < 1/2

Нижние края 1:

Downgoat1 края

Downgoat1 линии:

Downgoat1 линии

Upgoat2 края и линии:

Upgoat2 края Upgoat2 линии

Метод даже хорошо работал на особенно шумных изображениях. Вот нижние края и линии:

нижние края вниз3 линии


добавление

Получается, что среднее размытие и адаптивное пороговое значение Гаусса до преобразования Хафа работают намного лучше, чем обнаружение краев Канни, в основном потому, что среднее размытие хорошо в шумных областях. Однако проблемы моего первоначального подхода сразу очевидны: на некоторых изображениях видны фоновые линии, а также лицо козла.

def is_upgoat2(path):
    img = cv2.imread(path)
    #height, width, channels = img.shape
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    gray = cv2.medianBlur(gray, 19)
    thresh = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
                                   cv2.THRESH_BINARY_INV, 11, 2)

    lines = cv2.HoughLinesP(thresh, 1, np.pi / 180, threshold=100,
                            minLineLength=50, maxLineGap=10)

    vert_y = []
    horiz_y = []
    for line in lines:
        x1, y1, x2, y2 = line[0]
        # Vertical lines
        if x1 == x2 or abs((y2-y1)/(x2-x1)) > 3:
            vert_y.append((y1+y2)/2)
            cv2.line(img, (x1, y1), (x2, y2), (0, 255, 0), 2)

        # Horizontal lines
        if x1 != x2 and abs((y2-y1)/(x2-x1)) < 1/3:
            horiz_y.append((y1+y2)/2)
            cv2.line(img, (x1, y1), (x2, y2), (0, 0, 255), 2)


    print(np.median(vert_y), np.median(horiz_y))

Вот downgoat8:

downgoat8 thresh нижние края

Контуры (код не показан) довольно хорошо обнаруживают верхний край козла (позвоночник), но не в состоянии получить всю форму.

контуры

Дальнейшие исследования: OpenCV имеет функцию обнаружения объектов на основе Haar, которая обычно используется для таких вещей, как машины и лица, но, вероятно, может работать и для коз, учитывая их отличительную форму.

Распознавание 2D-объектов выглядит многообещающе (сопоставление с шаблоном не будет работать из-за масштабирования и поворота), но мне лень разбираться в OpenCV для C ++.

qwr
источник
10

Python 3, NumPy, Scikit, 100%

Этот код запускает обученный козлом классификатор изображений по одному имени файла, распечатывая «Upgoat» или «Downgoat». Сам код представляет собой одну строку python3, которой предшествует одна гигантская строка и строка импорта. Гигантская строка на самом деле является обученным козлом классификатором, который выбирается во время выполнения и получает входное изображение для классификации.

Классификатор был создан с использованием системы TPOT от Рэндала Олсона и команды Университета Пенсильвании. TPOT помогает развивать конвейеры машинного обучения с использованием генетического программирования. В основном он использует искусственный отбор для выбора различных параметров и типов классификации, чтобы лучше всего работать с вводимыми вами входными данными, поэтому вам не нужно много знать о машинном обучении, чтобы получить довольно хорошую настройку конвейера. https://github.com/EpistasisLab/tpot . TPOT работает над Scikit-Learn, INRIA и др., Http://scikit-learn.org/stable/

Я дал TPOT около ста изображений коз, которые я нашел в интернете. Я выбрал те, которые выглядели относительно похожими на коз в Тесте, то есть «в поле», сбоку, и больше ничего не происходило на изображении. Результатом этого процесса TPOT был в основном объект ExtraTreesClassifier scikit-learn. Этот классификатор изображений после обучения (или «подгонки») моих козлов был протравлен в огромную строку. Строка, таким образом, содержит не только код классификатора, но и «отпечаток» обучения всех изображений коз, на которых она обучалась.

Я слегка обманул во время тренировок, включив тестовое изображение «козел на бревне» в тренировочные образы, но оно все равно довольно хорошо работает с общими изображениями «козел в поле». Кажется, есть компромисс: чем дольше я запускаю TPOT, тем лучше он создает классификатор. Тем не менее, лучшие классификаторы также кажутся «большими» и, в конечном счете, сталкиваются с лимитом в 30000 байт, заданным @Downgoat в игре в гольф. Эта программа в настоящее время составляет около 27 КБ. Обратите внимание, что «вторая группа» тестовых изображений не работает, как и «резервная ссылка», поэтому я не уверен, как это будет с ними работать. Если бы они были восстановлены, я, вероятно, начал бы заново, перезапустил TPOT и передал бы ему кучу новых изображений, и посмотрел бы, смогу ли я создать новый классификатор размером менее 30 Кбайт.

Спасибо

import pickle, bz2, base64, numpy, sys, skimage.transform, skimage.io
s = ''»
QlpoOTFBWSZTWbH8iTYAp4Z ///////////////////////////////////////////// 4E6fAAPR
OCLRpIfAbvhgIAAAAJCgAG68fDuYNrAwQbsADQAKBIJBITroq0UyRVNGVqljJVSvgAAAAEgAAAAA
AAO7AABugXamjQYyCIABQ6O7LEQ2hRwOdKSFCVuGgF1jBthaAUAAEgKGLVAAAAAKKCVFBIFEFKVE
DQNAaNPUGjTJjU000G1PU0ZAaaGJoyDQaDaQxPRP0oZpNo9NRGaJtRoaYmmyammnqGAjTBNpG1Ga
mT01GRoemTFNnoRNPZCm09pmP9VVVBlIgAAAmgAAExNAaBo0A1MA0ZAADRMCZoAajBNMGjTSntAC
YJgGiYJjU0YNTTCYCYTANABMATKHInox / 7VSqoZMgGQaGRoADQaDTRo00YQaAGgAGQ000yGmjQNG
mQ00DRhNADCNAAGmTIZGgaNGmgMhoZNAZDIIp4EBNACNNEMmhUjTyJ6T0h6k9qnqbTU8NCnqDaTJ
oaabTUaNqG0jIyG0T0ID1BkaGj1ABoMgGgwIxNAGhkGmTCZA0Ghk0DCKUQECYBMmIEyJhlPTU8k9
TGmpP0NNU9tRomTaU9PSep6UeIGGSGJppsU9MTKbVPyFPZMU8ET9QmmnppiJp5TT0A1PNSeJknpH
qb1T1PFGnqeqeNTSemyaT / VUEKiJAQp4JtJ6iTZNQNMgaabUBtRtTymxDUaepp6mgemp6ag9I9Ey
aaM1NGQaaDQ9TNJ6hoDag00PUaA00PUB6gNGR6jagANHqDT1DTTI9J0gKvsPxi9r9nnM1WbDVUTR
nBgijNiWaqCjE4kzhxREVREZNmqgdLCqGJUXEg0K0IUotA0AJiVHEoUpQUI0CFDQUFAlI0FUjiQc
SjQA0DRTQI0jSJRTQLSrSjUQlFBRSBSNFBQAUo0lA0CYjECNjAjiEaVChEKBKUCgxAi4gVxAA4hQ
cQABGiIMAYEDMI90oGBe6yPBxuR2XhdxeZ1XL5AOe46 / lgb3BhDEJzJA3cev7vi53o25xTVTDRTL
S1W9eT6bsd7nyJqit + oxYIxWMYiKoqLGDERRMbmDk5 / f6rkb21xwxXFwxJYkqLFNSVjGDBjFGIiE
qiASEhEiLteHuvnMwqrqQgKhgZCZiYGIVCJEec2WyYMxkzjDibGEznHXdX7PtN84txMODGGnHFxY
GsFUZxYzGSoxZjnNNLO / 3fouWnGjjcYxnGCc4xVGycVFEZjDZsNpgzOM4UxIRQSGr + hhCVYTQEJB
MhACqGoDJDAR + С + VeBCIQEqhACCRSMAEqiA0MARCEZiZkNQiKEJACuhYhx6tAQhhet2tXbimsqnn
5qIY9C5JNHDqZp2rlRGwrWGuGgdu4FIYehsHhUKrgtTZWLIJqoOGsaUi5c7iYp2n + 46rbNtk8pSy
TJoqTh822poWQW92oaGuNk4 + Qil6VnzEKp6Lla + yUQqzH9N4p / vcI1WYVfBWLk53uwVcjn / iaf1x
kZJrY15LvF3c6bDSd7rtIF / CIeJ5ySSPDS8WpbhSth1jnyu1DFRb7ulLM6NlFMEVOCorVWdxjepR
5Nc0vgBvyASUIIJt9qydSewF7mdm76qnXx7NXCsl8ZDDG2 / 7KhXbsv3S1dTtXOitVYaUPrsnj + НГ
R1MPnB8p7Hvdwe4eXxf1Bf39iVuyg9r9aweH4Ht / NfXOQ4IJ + q9UqxkeHy / Br1ixpI39nqf5 / 4GM
+ LgfXIgl7f372D + VF7 / 5D + t8jLCs + H23tsPj / lnZBkV + Xn / mfuvf + 2anyF + G + bGUypcqKqpb7iCo
QlBCSaYTfNYNeoXO19viV + uYu6lckm6OXj9Tp9QzdR204Lp87r88k9ULU01rhNPleSE5XK01Nht2
wB94gHbgH5aAB / 4hTt + y3OP41ivChK2SdsxThs4cw8p2uVsN5FTvdbYyDqkHKOdv6MDXJtk + fP9U
5DFrCIhv7UQqmETgJWZWhQhDBUKlJVKRuLBari0uxZtg9q6L3K42KgbA1aXeD3ypsAhWxqK9TK59
zuFDq1sYAWeBrNuydhlVPhwDoa7rs0xZkRXtSwuyYXtqIGsoWv3eglDKBjICrev + т / pew8 // j513
S4f9JIPxCWiAoDeb + iULXivpuL37uuEfiPr764B8OuKs1SrGVPUwelyHbu0yufCuMGLcP / 3fWryq
1UsZhJYJVQkrsEZBqJpkqWQiaYqbW9MsHsp75bTgxTNiy1cdasS2yU3GLG1jf1ajXwKd + 5HugAoU
tkoFOFTCSlQpUQxsyVjWZPGsCg9gt9j818V6Kvl7v5rK1tfoqfGfF1VAAENVQVVB + TUgAKqgAArd
D3XFc7OPq9D / bjG5yjUJeo + UtdmF4WweIIIipSUqVK2ISSVr93 + lkXLVyElqLZPL12cp3sc1CkPL
5IwHHuctF9lda56rrWDJy / ueRIKFF / FvB + EAAlCWZzg3ywLIOUexFPhVz68zMJ9jK2cpO2Kkma3p
StTr71R0nR / Gqfiqg8EojIZ3LNE7UrqlPVIysrlogNqiJzimFb6yLlGnVjHz2EdpNV6XZ8iv7IdT
nN0ut93cJpaqV0cEixL2TzSPqmoXvqB6IKDm + qmocLKnh2CWwsyqsMHtlV2 + rqNzX3nVoN0Cg6vL
U2OQyZ + XMS / gMc8yPKp5AIPqjjxNohmUc6ulA8IbleVQ2twH / Qc + H3QukwweIdinUphR6cPtB8oN
K8g / jbgfO3A9NhBQDKIg5IFDqBF2Yg / kQT0lA9NUPUVfVEfWEfpiJ + hQ2IB0oDtETMCZdHXCfrQN
qrthLhD0RNcJ6Y9EulXUgXS + u3LqAPVXav7EuHVO3DzA3D5IeUZxJ4DyIIPZ5HqdwIIAjH3M3O7T
zfUe5873xTd7r3pwJvknerhHzvPn6vzoOpfBAxna5nUVkZ3qsbqsQFQxLQ0IOKkjliCAI5znlbm5
ub29vY6oAAAAAAAAAAAAACqqqgAAAAAAAAAAAKqqqtGpqaM + fXWvZtXPp19ObTpWRyVSVzSaTnSZ
ISFlhCDkJ0WkkILE5KpK5pNJzpMkIm96uSToJKUXRg975M0XKsINJzoLBlWMGQ5RR0nKkFlFyRjJ
ISi6MHvfJmi5VhBpOdBYMqxgyHKKOk5QEVdE0FESD4xMmcIxOCC5hcb0F7mAXSUBk6EEkTEcoC8E
QpGkCSBCaqzovVoRckouU1WMZM95vNpRIYxVQaAgxG50kKDifCRxkiRWKxU3szGLmZHqkShKT2Fo
SIIujEYQg54EMjYyhJ5RKKM2hqbDJmxkz60YxYmAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVVVVVVVVVVVVVVVVVVVVVVYygAwAAAA
AAAAAAAAADGQAFVVVYAAAAAAAAAAABVVVQAAAAAAAAAAAAAGMYxjGMYxjGAAAAAAAAAAAAKqqqxl
yZAAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABVVVVVVVVVVVVVVVVV
VAAAAAAAAAAAAVVVVaNXYZ9XJsNOhzoPjATZ7gjJHGZqZvMIwUCNiA3ON7mg8lirSKUQUpMTI0ZQ
NxorCSQKMFRGdFjaEZPhGEoxlKUgAAAAAAAAAAAACqqqgAAAAAAAAAAAAAMjNnzZtbNq6 + jLp12r
r2pm17IyPWUke6TzZ7lg4jfIoCcieoRCAEiwesXIqSVnqmaamnS1s + tra2wz6NGfV0Yy5cmXV058
2tp06cYYAAAAAAAAAAAAAAAAAAAAAAxjGMYxjGMYwAAAAAAAAAAAAAAAAAAAAAAAAAAAAACqqqqq
qqqqqqqqqsZcgAMAAAAAAAAAAAAAAAAAAAAAAAAAAqqqqqqqqqqqAAAAAAAAAAAAAAxkyZcmTL5X
UABaQRUCkFAEpBFgkAQi / yAIiyQorG8kZN9kMZMAVA1v18dKaO4pB0771qIqBiQVUIgVU / 3hAHaM
ggEApEkkXUCueVjqIqwv0JBQVdUQaqXTh01SUQosK + NiU2qmwMHABALMSQ + BUXW + 7Xr09DlfqrdX
/ 939Xyc9YbJ / GjfTHd3mflYe8dzKSXup + г / HbwMZ8arVvHPdveWSm6FplrPLVmr2S843G4vE5O65
PJ4bC8DU5Luf + 6ve / Xp0 / g6un0Hj / Ty0fn2O99Haarbd32V / Dny / Qc5sNf / zt7 + dwOVu9 / 5Os2eg
0vXc5p9t4dmD1nVd / lairac3oOe0vZ9V + FSDB + LsOvxsPp9V1Gn8DR6 / Y / 7 / + рг 7La38WU / 06fv
fB8TVaynfbXa6qUu6xdNqP7 + FLY62em1Wnydnr9r3vjbDxtXkWeFrtT / nW63X6zw / E12s1 + Vsrk /
Н2 + P5HkY97JyLvk5F6ud9cu5OTj3NtSvbUrsvL1VdclKMCEI / KZ + htbPr46uEYwjGMeEz24bnash
zXEx3HMzQQZAQYBB9WpqbuxABZyiDy5zuTwGgskeZ3vWc + ABzZFn1QCDPvZ0J96TVM1ENETFMVSQ
UxNFVVRK + 690eoABfv372329iVOAmoTnKmXpwCVlmZmoABwwAAAORAAzRmgM6AZ85kAc2A6TpQ0Q
AAAClc5KO1AHe90CScngj / ABrQBsQABkXAGUWSrUqVKl9 / KLRiBAYDByIgJv / fkVEE72ARUN6QQT
av4jrx7Z + ANFQeu4oaOQ2IIM36MBCY6 + yU8Yn97qjqIuOZ + 9iKAou4t0QKchQhdMMYRhCMLUcv + я
EQABvlVN9lZZYknOaiSc9 / oX6WU4KgZgAAAAAAAOS + kDkWdAOdAAwgB98aQAAB + 0dmnKykqA7gA7
w7yc1kqA8EDXNWbB4oANoeQLuMAF9XIowfMQzlqMIWrUYxtWoQjCNq1CEIxtWoQEKRQoVCgAKBEp
QKBWke4kA9PC9hAIHEkBD / IUkD2TCAb / pcCjmkJd2AO / lFXsIR35QfWwi + hkF9fKi9rCIie4gRfE
ym3CH3EHl4A9hKhxJ / BgXBwisStCQLDeYA3MB6cvZLeLKyyysFJWKUJMzOQHtgAA4gA + UAHIB9EA
M3ywBy + eAAwh0AA6MAAaU6tpQkUTAAArsropQAAA14AAMYAcbi0uNS49KlS + / Qygn9okGIUPw6YE
HpA8SfNPy / H4T7sxEA7lBBAPSIIKtIVMa6caqJDD5OfnbqJb71tVM6zwsIQAUgIwjvsAywAMqeVX
ве / 3pznOycydJCjgZyTUAAAAA + gD6gDlDlA5YDPAHOgAYTQDog6M0QBpANIB1z9llcp0nR2juO5A
AqropQAANca4P / DDADGACtWDBhnIQjyV3R / 66ny2rhCMIQh7rcOMh + Hynd5yMPK5XGdbifY0PcR3
GEI6fh9yjloxhCFqEIQhDeoQAD0YJX8q / evb4nOY3dZSk5qMzSmYnOgAADh3CgOJAA + eAcnyYAA5
gAz4wgAHSgNH1BogAFlcp9lMHagAWJaidO + AAAAAAMYACsGBCHpIWoQhpIRhDP6HjctrOQ4o6Lzb
P2RpiYdZjQD626Ff / PHsBn37P5PufLqbcUiBgCMIb3CAG6gC / VVOq9esSkUoSpIcDKyb3GZoAAAA
cYA4sA44MAAMAGdObAwQYQAH4OnAA6sdWDsHX35Uk7GgAAJ0lJRqQAAAABdumMZDbAKxRgxhnIQj
nd0ydDouH8vuGWtQhGEI6jwOK7n50c9L + 2В4 / dPObGELUIbrGEY2oxhCEN5iPNAD1QXr053vTWWJ
SoUskoK67KSAcGOCe + AA + IAAAAPrAADmgAMIB + M6I6YAAdUAdZRKnYzoDthpgFKWUkoAAAAABcu4
wAFaQwOWhCEYQjajGHm / S8dGMMH4cYwjEqlQCFz / 4edmzVADd7iqXwZpGvJyp7vSne5fDfw4NF8z
DLQjGELUIwjHeYwAADb0pelJOe7ybtQr3idApNwGYAAAAAfHAAAABmwcwcyHMgMIHPujB + UAAaUA
TlNKgAfy0wEpf1SpQAAB4oABjDGAVF9WKMCHFWoRhuXv7UIxhCEPHtRhCEYww2BF2WXkBAfUgEZs
IrLoyRRB3bAo6GrNSCDMZkPwHld4ZXqqfWZHDB1X8PQ4ftgUL2AQAJykYAAZYWWTy9 / fJSpOc92m
KTpve9Ue0nOlFAAOGAcJxYAA4180ADNgcqAc0ADnsIAB0wAdSAAT / dZOUw7XtjtwacUknKYAAANg
AAMYAOLS43x0qVKl2ZnoEoqc2QDW8f + sTtv / A1AIMUSdJOliTgaTCVQyOZxmCx6B7fdTji1wIOcL
QRhAMA0qVKupUqVOAX / V36qqqUsnPelCuzfqTy4lKlJ0ODAAAAAAAAfXA5MAwQAMJz4HQh0gAAAC
yVkqKABpgJqamlGpAADXA8YAAxjyQF9WKMCDkBWBo / f3nATMdNqPaFDUAg3zQSIg + lM20pcyohl9
R0H1pgoVnawZP7O20Wvxf2LML7Co6hNxCoxEEREIRjG1ahHfoQAUpSlKZErMmyuuVlcrLLK8zfvV
11VZV / 2d + / Vl6qqqvd5iqqqqqrhaqqqqqqqqqqqqqqqquIqqqqqqqqyePyc1k5OTkfLyMjIyMfNY
/ Ky + Р / au3bt27dzdy5cuXLlzBuXLly5z9y5cuXLmguXLly5tOh2nRbTabLF / Nh7PF6XF0eLi4uL
i4mJiYmJiYlvY4eHsuuw7du3bt27du3bt2 + 3t27du3b4HA4HA4HA4HAu9rd3d3tLu7u7u7u7v2N7
7G93u93v1 + rB5b7eYRBmhGtRBsKy / GX7nOB1 / E3 / qXrb / 3FEEsgr3NOugQYgYIUoKUpDoMnMf9JD
lIjzOcRB8V0nUZ / J2IjPhEeewNb0JbaLYXfo9aPzTK2tiN5ALOEUiEbNlrUDRlB1MS + eEEA + BDJZ
+ PbCQi4er6zV6K2iiCwOAQHKAQEIQIgsK8HQmk + 3XIg4AbHDyyj2C7CQc / V3ix6TAb7qDRb / POT1
ebs0bSBiBYgWQEG0bTBQpV + hi7qnVA6OEHS20 / р / 23o0fEmnxQ1qhXQkQrW1g1sHjQFrLvb + iAWn
lK9nsvYQQqUWDrj30rLLFl85s4pl / CToEB2gAIQS7ZrwaSB08E27237snaWSIO7jXauo4q + b4OeE
KpUKxq14UISbjbs2RBAPUU1ezYCbpVcJlh3K9CL7 + BIebaJl1OUvpTI + aCSVpzU + Il8r4GQDpJoG
gGgR2en5fPQIPnu4x7XtkzByrR1QKTpsdMNCQYt0AaIlc2aEEAs + qCTtZfBwYICmu4fpDGr2Hjae
psCC2AKD6apD39bTAGwy + BZPQCAWOGWUaOFSbfCbMAyqoOAQQ6SDoATyAMWOZrG0hbHBBALXsyTC
ZJA53b9jyNZQ5HHH2ZGk / 13f / C + I / ZDte08YgB0kqUgG7pXT1ABAMX41Lbt4d1gi3BVNUKwAEJgH
cMJzQVfUq / х8 + DBFgv12VXO1Fpoq5i7xXVgVAAuQC4o11H6opZ07GzB1kExvmeWckaqbkCRU1iJf
Z9gDVniZ8XUg + zZ2lCTCU5qcdLqgrZ84SqB + QwNCdQVw8ADECL + / t8zQ5LrNT52orqvD4m6lPzd /
YyoxYg4ob1W / JpNtsPQ0XLzgZ0JpghiJlAIcxjlbbdBBrtkMjU5 + BG6 / xqfFgvYmQAvbmxoIE / CD
BsOq6 / jpUl4ocf6meW7vnUb4YhSRX4MLMYHhJd9wgEGFLb6HBn4AED58IDj9n4vX7m2oFVibn7IE
/ RTRnVikkSXY2vf / PBBqNDu / IurbDfSqtJv8Jlu9zNdPEr / OYWQgrECDIzfa7rEYsmcgAJgIADr6
a0BBzs9qX3KO1uM9LgaY4 ++ vIxTUXMFjPWNf / n38HGXqT338kv9mub5gWYIhjiEEDd9VS / QgBAP +
UaOqjT0PBqd3W1BPQqlPNiXksoF4rxC9wqpwa6mmggb53q4Krla2yg58EZ5RfgS1wDIgOADyo6q3
fostZ4HbsAAgHi0VzeKH / GVqr7zs36oA4UJLASwUkjJSX9EH0vMrq4AQdzftzQzEGxjeY48XN7Ty
9eIT2vRrwdhb1lbJljEebtaNNsuay9FQ0NROIeNOzwh5q6ryfpvXeFFDpIApEPrRApghYIiEFM32
n1P8enSqlVMLPwez / + 7nkJ4qn04P7wd / 3UgIYz4JAQ9LZyKDz2ckVXrtJc3PJ23yu2 / PRB / VFKF /
PAnQeXIIa + BU2EddC7OBF4kAOGhK3F5nm8SACAVVZvxO7 + WQArXQrfXwkJA1bgDqrQsJlycegjze
PWc8RzzpycDyyCAe9lBwpbONqF3TcfVbssZBWPyz8cvfwXwKSAUhiQm7lasRaEEUiBQv4CRCK4r7
0 / ZmwmS5Ks77D9zvJPwJPrQK5P7QZpAF4c2zheVZwLVWQE4ke22p / W0HA3mMM + PEpCsluAVqaYux
hkHopROiQKJgKQH6Q5nUHhx7f4fynJHZ7fv + NYbllgCn / cNUv7bFd8 + qFgeAvwB ++ га / JVNTGN53
IB4WRpQQoiVv4Q60XPHXjmIfMQdt67x / xno + j3jw8oPPoFGJxUoBg3qTG2R3KnRoEz3EJBVwrSlW
MSllN0Ngn4X88TZSSn4yioJoJgwC9nXql7l68n50Vw3ZeHSYAIB6GcHhVyOzlclfgFIXgBwAUD0Y
QE + y4AQ98kOYiVVDEicHJ7vf + ж / 6Pgus8Aem43Udv3PNO76n0KYLyZ307TUBna8nIWynQx2oTMU2
dsCW8ItuBERCQQo2 + uuJ1R6nNjqxu / 4477i1foYXNYL16lbIPJgNFAcpJfRZqXv1an470C2sEQpa
qB78062iGy5rWmC7XNTOQxcOtlMlzPAzFbXONFWMAeiwgicygj / F8w / KEH / BCEBCCQe46qXWreFI
F9y41ErQyV + zGVIHdiQ8IdgeFAA0ENQYGGVvxJAfiSfaWnSggzfIveHGXibYPW7g3HaVONwuUpvX
+ TONfVrNC0QkhtuZpcGy9yii1YMQLNs9b6FS / J6TlPa2Vz8HueJYtMxYgxlY / Mxw9k5IIDkEFxsu
5pMlm13gS5cnrZoLfi4MJDy7AhQA7ANx / 1w4ckJIIn1dz86i4qNLZVG313vETqtgCatnCWfqa3 / V,
aiFaoGPVKE5fBeh5cXum + GP0Xfqs7d84PpzfD + lVlIIQQECDekA + 1 + DmPqshl7IBv4LPAN9U4Hv7
kyOuussZHkeXSmLJbEG8AN4AdTJ8SHas8Lh2FO7IK8BfiEAB4gvFuCYAAMyCKwAWXxhlysSbKCqO
X5oEwpblsAcWnxmbYkhsCF0JLXTv6LC + L1sfO1IamFQALWhg0BKtHIG / pvBjlrCol / RGt72YlSDM
KgEqBPTxHR / 7gUAYIwM0ur / 11xYqAPq2AWj9vikGf8kgnEZfBftker7vGEYN54bYwDwMwPr / tvqe
78KJRD / L9r / 4vUG + s7zBC + skgZJj9JWq / MFXMd + t6sAYegSGJ / eoe4SFUEahIxBDBTE1BCJREQVU
U0UjMRUVIxMyITQjQkMTAyRFUQSoRUTVDUSECFCWoyBFIyERREIlav87qAiIuAhiVRkggn2JmQqC
mggioJIIKaihqQIgCBoq1EiKJoimJCBiaiKiImZGoCAlsO4Q4pEERVJBBCI / bsYKjMokiGDVMgMx
EqsbGCiCqZqBiZMpmSEjFX9 + Yie5UICUkMTNDEEUEGpUQkQkU0QCIiQqs6pvC42JIkSiuAMLIh7h
cZKxi5zGRmbjBlfkNThAh3PMLQJO0kJFVCY1ZjISNVMFUb45gBSU0FGZ7GfzasbgNWogMLEOxBiA
3rG1wILGbnCpq4xVjARnwHiDkCwWAfxaEYGKrctSJxcgkTHw352YiOM7UEkEEZEV5xcYEqgL4vLJ
lQfG5rWIQgJDVv4WZ0YH / UOBKMg1ICQJ0ScqApiagQi9UNwQOy2OOgHJgSAiipcTFMahJWqVEPAy
OgyCCIMwImrAQMwd8AsnblR6VGR1PQzA1mxoQ1UpndpufbhB + JREmjK + ZhXCwnQCQUzyo + ux9AvZ
UqRpnWxAQiNeRA4T0JrBB3hgs0JhpI3389AitYytiEql9bdeYIA32QwUAiJqUTuVAMSFRW5ArSph
X2wycKGIQL + 9E0FImZkAju3G9BgTj58nLbRhhLLaavCpqgl1lhwYHDMQ6IdqAJEDXb2mC1DAiQwu
QgG3tDdTjjq2TxeQQ497iMECvvmdg9JZvQQiuupKGgwcAkAiQhiRAICJkBCAliRoQXZi + 4bX6Qqf
54BVUVW3svV1AAGoDVQahr75ooWMQGImINv4HV + WYAztv1YFAagjjqoR7LekYVBEc / tyMXCATHiN
QB24EH3ogGK4HUFw1QCh9l + zAG4DhDKul9eOWUwAFzoYVdFIAuEKpeV2N0bXVBO0 / pp8g6 + hDST9
JX3d6Pdlm89PwsACoAq / D8FdDO3hpyAAAKkpodVQCtghHXJ2RErK5wbs9XElajJiizuE85V + ZXLd
Pyvy8xJOupddZ5jUTHTGEXWTNrTVo1k / u32XuDO8fpJRFzX2UKHpyclub3QmrRtnLDzSjvgEvvB7
q4UBLarBSmLSu2vTbrO + ZSbdTc6xrbEWwt8 / 5hTso2Ra / 0agqAKv3nwdsPoXaRpJHO045EGgd72y
WrVszfzjOcVKkDCwEOIem7nv2gYPreIIBQhFovlA5DCNUYscEiTK / 4V0YQc4zKxElKSGrEyJBRhK
PAJTLfnOXThkGrlpBRKpW / L4WpuVL56myXL4dfGxr + vy6pUp5lp8s1 / 1ouKjtqrb + 04ioBfm1QTY
SIn9ANIpl1WXToEahjlGBu / sZIfKlLC8pB0gZbEbvzUFDMBqCIh / tfpxRwgnx1 / 0uHx7RPieotiQ
BYWISqFAQhLiZnVVycI8REQ0Hj7lTBFPuQjs + e96w9Ab5IiX38YHg / 3D50OJjzJLSQ7bunfZDrrG
EZn35Y4fYQOEYd1c5j2D4nxPMEKJfASSWsDZqBSRwqEYNCt + 6A3vDCJarMOHPPGt513RieQyBFjJ
Fu8a7CsC / pILluBQEK4XWubGgI + Wdp5FnlHAGiMrrzB4ZyE2tsGErymPlkGDldc1J56XsL3uXUGN
4DjdYteEsK6aeWGMHQvhmLq81RyULQkPDuY7gaQmBYkohgb3TU8TrR5gannWpg + WTydjeeD3uUNA
2z63a3xxMLTHLNaIGAYkiPGHTIkiuaTyjnXCZcOvY7rJsRK / kyXWF1YxE63khaonFdmIOIZCBo1S
8dCHtB / bqoGF12thHvgxOedj4ypXY29TNWidorby8bsa3O2fAMszfcuZdsYrMudt7PnuznKXFGfC
bs9lNAERIRIXFE0ZCnSD3VOodpzSGr3hO1zz2dgHNH8x1rpXbTOd4vwiltm22MIboTvvrrnaMgO2
aUPDivhZZyHjo1YkPjedqKEBPwIL1YXRJUN4K3AIa7Q1hIQhJ8H0mrnO751mGYvCvCzd2vFl2Kdz
OdQLw7uFY8JdlkTe6SrYxCCC0N + RR6sLKYFQXlbMGu3PePLKtVuWMIndDDyJhyYbAjMxJPCltbXQ
dCxqKt047xOWRCvM3MGssh3L0aVfDoQa9SUWfXJ2 + tB1ijxCMXFzN68Awy42A7yi6e / I33xXYdoT
Cum8d6bbsI9eT8sLTdZwmoT4dvbzhMccnztjnbArbS28KEPdhw2LxfhaIiQwEdrrGa23skoq + B6X
yQCRmx8d4NB4u7B3d + 1Ad2dt4TgUDHclmXZmD548bQgbpOTc + h89SFWFt + / dEzQZAb3K6b4FHr0P
SvWlxxUdgdRuFlIZb511xtsmHbaRIXHDLYa6LDjd2dd + XDnae3fkT + RhowXYlgvFLlArArdxprHB
2ei2bilLTbbjnrpPpjG4u87QzjfHDG2PQ4c + UoQoPQi1GAhYtCooqWg + D6NHfW98ZvmkXajLdOVL
OaV6zv3Yd + UOljp7RCtbu + lqpqTkvZOe8quNevfvRQr28tcNtN3djfIsNOr9N9rZwMCI4AwwZY3r
Q91OyY6Q0jpdcnJHNGg3wySm / Lpkcl48Uvzz23RAN6SUkZt / CCivGGMsQy3pe7grdOzhlr06hTIL
77MKXMyjnhJCpHpf0w1vhmIcRDqWPZgZpHY8hztyj35vV2lIQA6cuV1fHcdfO7ud3c9m8Oeuwhll
iFMK92ZjaMsN3TVq / G + zXvyhy3JyyyfQuVu2Y5gelrdnZ3T7Z + Pbj02HeA8dy6lvQXj1319C0s0G
zbp26Wd81DXlZ5Y7dl5Wk / p0xw5deRdeuXVvBQ7bKWDTinWO ++ za9Dl1UuJXX + V6 + RKp7Bfv58pv
7szEu293TG0Lru9g0jod / fLWW1A403 + VuWVfHw0vs6FXdDJewpvINawyIumNm3b3ZO6eWG0xo1XE
cJUttx1xnV07u0516EASDuy4aEZdfJsqePd437m32UG / y7e6mW7yV7hDndG5PDC8e3m2GEOImshk
XECUiDG7xwR1pC / ciBt3gQPtrMmIQ7xRKGCJWOC3YQCrGON3BFqQEAicIEIlzgdVVQBVrmgd4xAR
AOpkqZKQphqvHn5Bu2ivV6CMZaMmkoGXCUFcRDC3sK5VM2QUZLe5VxQLXLXTu5W2B4Bj4XePi01m
5xwxtdx4U8nrloM8OnjTyV9T35WDaCCGu7jUmYhk5SZCcUDIuN17rXB + C + VqCqqoB93 / 0 + AXy4cx
I4e + Q + R · K30f + 95q4G + nT4Rv2MSf5wwSskQvMBCgTSN4jJ80RzxSTKq1NU5AFVpsg4AW / CmH1Re
pH1Pn + flms88wr + lKrN + 5N8RQXZfBc / TxbCjqbDwu3S2f3kk7C12cg / Cep4AOctOLvDbOWWGeMx7
LoaV2y1gWvwu63hPC6q4moW6XZ1nyryWuB7wZLgy3EDoXaaJYHOuxlwvcm6utwbo9q8DXKOG22mG
T09MXGGAxGkGt5ZzkRPtZTqhMYNi6l9j5rW / ohKV1dU3mteKvfSyL3uC8mihsFDw1jCt9bHS5ZQa
VIM05IlNE4ts2rGNhrpaYNzWnPme784eXaqimogkoiA + yxCQQwwGC / N32IVAM87DPdj + NQHqb3XH
MW + GtR3ZimnCBDwLaQX93rD5D6Pw4spVuZ9JRMjI6vQH0SE0jBgdWEHClL7KNYVAQYm0XXUBozO4
mthCt0gUb7K4vrlUpkjr / isfW5TseFDnDKusXXndg6ulr2yuvtJ5MkBrxMKWmN1uRWDgqnWs8mxM
67xWEqQmWSTuD5b / OH8o / эфф + 7T / 39M37r + R5ZYZ5es29pvL0vZ7ezGAxGQze04l6pvaAIfElD1j
uyCH7BJW + ld3zg5AvvlZ4z + D9K64KWyiVUyrs0xR3pejvdT1tL7vah6PmZNWILx3wpnT2J2 + w9o9
9fCuoRHQO0QLlG5 / peu1W1 + 3aXxkPXmHfam6KyERpdVrPu5pnGHOVOc3WcQgcPaNzxtyaPPLKTht
7DHvt9q0ekL9 + WEluHldE34YQEFrKwd2PY1dpTRXuZAWFY9L8MOodeuGD91x19mmWSdmA8DDQYZZ
5SVe / U4Qz7cGvBwR8Onst + nLN9d2yVrySLwjTfAE4XUSWoakBBkcOFRabcn6x4dkVtBu09nsG / FO
wdk6w5YLFCjQzPZd + qZ4boVhDVya8A7t177LqyDwxCN9cd / dHbnJ2kHEG98rUjEIxg / tEQELsG7s
tqXWlZrCZSxIFvdDZLtMjK6ImxEd4V5IVb9VfKb8uV7WcqBdXMRWI5b3cd1RMN + AaYsFEbMJQzzW
0XjyZ4ZZynCyOGN3s / а + Ol1WQ7nVrJenDHnqQW5ZGFw0AZC6unfWLmJswO21wZFFdXzE9drW2XeL
+ 3x9rupyyfQLsDCg4vv7e7Ddm + jm4Yr3Z4xjwXE3jxBxEOqB6X0HU9SRUtBRRLHUtShCEBAQgIV2
HnL8NMveS9WDDgYzXXahUuBzXMAgkaFrxPU7dAIQCKmanmTNUEd + POeU5vi9BQ8F8dwczygPKPI3
k97ou + 81vojxP1F0z14zxt15v0sO7fY7PDVVUDAwMDAwMDAwMDAwMDAykpl56wiDx + X7nyOu / W87
VVRUM1U1BcIYqqpYjnFAdIO8 ++ 9Z + 18123c9z4ncBB5KCebkR / F9t93ke68F4N5YPxPrNOXzAgqK
IkgOyEIQgoQ4 + Ecqf7fxiQMzG4Dzq + Tc15Pv8WfiwVYdh2AY / Eu3ZEEQREMFlDDBEEctvdqXny + Н
7vHA3fh4vt8xfP8ePyd5LynAFJ + 3Ptf8e9 + S53hiKGmeFogi4N7lelx3fFP1fQXfeclgOhp + L3qf
LPR3UIgwiDUtmDYZbbuXRBlskgmkgpuAigqeg4x79wc76P5f1Hq / bPZHv5zz9fu + 0yY8N0fTgekP
CPCnCegGfRS + NOdThqp4QiqIh5MkgA2srhW8DlKNBIAOIHLdehZ1rhPaf86uqfIIdkjao ++ JGo9T
w86Q0VNwuIOHhUB8Ry / M9Z + Айз / j1 + UjkpzxyapKT / XCGk + p38OyE46gPHBKFWigCuPMZT2NyOQo
D0g + i0R + w6YMHnJez6v2mTvUkcfAHuwFa1AQEhvRgwP0cDQZiTyfuZR0ZzJazX8HT + о + d2HEQEHl
dD8wgg + V8C8JhMUV5CznBU0kSTFERRQVZcOJiimqZrOcll0AQfTfyZ77AIPSgg752NKA73Ve41QQ
c7pv0hiRG0RBwq9jnAxxrY9SzghQwKEKGOIiDhEcojKLDJUWG9PbyPgpTThagHYQEaUAgG1dSTs +
oXMbdx8Plo4sCrEWA8F9QQO8geXGDtv7l0hCCEIQuceSfAsjITnK8GtEtmNfDVrtswvLoA3oggGy
AEAtnDgBAPbysjLWUGRMP39lpcPFNubLXsAjCseDiKeGPHtSnG1B02A3FnzXY27bkRFwFyfBj8 + R,
fuwrJsqIOYmIgzgQZgIOB + LqPDsew8DsvYy3 / tWhPG1B6P59leYICPhlNfSOMAw5u1vbjyqOPIdq
Grwf9m8LwA7VLERweIe1VIJJJppJpHBWoW / uFtYQofc580Z / Бэйли / rcbfloWBaeQgga0RwJdh2h2
kh2hJMJ9BuuswPpY6f9sJKTg + dtQrAXANw5QCE95VQbSHDlyhDlJCaSSSYSQhdfEO0R + 71MVS0H1
fr0Iq8eT7dnneHUdxet // 3FjLpVfxuPA5vK6V66FHLYm / EAkgC9y12MngqL8pCfqfWqrN7gVMopA
Ktl7KyD + VWq1XQkhAq6E00wkEk0ZQ4WN8 + x7qsxHnhJ3HOftGUU00FkFk7wUhCp38yurSK + vlliX
KTHkDTt6gAHL4zVXzzuAZrZdF3fi7g8wAOq0IcQchff83wLVvY7OEtFGVkx / y73fCdEl8lkllliG
X5vZ / cKi932 + qA47TNANYKwHsxv1 / CrdJ4GU84VkMQH6ZRfkAiuqXpKo2B8E0LUFD + ECeVAMfd2U
lGnUr1SN96bNl2RIKsi5Vv8qKk65ZaTEWYHdMJz8GQMADTIBsOtgYFCAEF / wFR2NE1YzWGjZvIYm
JmwN3tt9sgI1 + CA93wQhG316TjKJdbFQD1QruumCcXb / 1T89JcWGYUqGC1vWFPOY2VNL + VnGUaxe
qU1ZldElC24hK / ZLR / kn68N99aonkCAc5kIDFRg / u3y5Ca0lAKQEBg0EjitScs3s9UWFaODgGFoQ
SoAYAUyD60EK6hyVeJV2nXubIAQC2rcrXMJgO7Wrzp2jpMkUEn21JIUvACkOwhpC + Cj37Cr7ndLb
VyHWC2rebx97BJWkOSHJFzQTpnLpSN1uL3qpGRkJvFEgA6 / 0UlFtKy9MbwFF9Dch6Cgh4PkCgEJH
Nb / 8mNdfaF3vfr7au3g2e9QY / ZvaEXsTXoqrr6Ki8AKcZQefTZ7cbZoAF30kOXAyCmFuIwF4UdLz
0wdAG + BTCHux7Zn0gDjB2MdwuKkEwkFDm7BQVG9SwqBBobKAEIC2 / qAkLTiVLH2CGVhR6w7 / zz2G
4qJvs / 4A8vRolTkZVBMIEHk / 0DY7B9m1HviOXEWHb1g0gDX9c4k1IQgnCpZb7goDH + EsATHHfW5r
LbGMAWAUPpdrgI6VRESgUKyE5IhMCUSAXF0OPutXyU / nldne719lra1OAJrDNoAcxAbsbiGwnR87
b212K + 23VUvGA31TynD + GeTAQd57WVlBBwfMfH2G9vVKnFU8bad5XlBJJEkiFq7dOqXbc5 + hUgkk
Yaa9Fz1zAwu94 + Q99j5oAB5qtyAfmp7WcjfbM6KL1gjHoSxkv5u99UuF6vpKFrj1olNXufcCSOvh
fd2xlKG / 7XF43ZAvvtmmwMSQEIN5zZVXBSEhR0z6p1kwQQIlMXAxuO6 + Sz0KSzlMz5WwmOP + 5Kui
qyT4ndILsW9CQYQcAodKQlQArUr + ssfHwtTCpILqqo / RgAn + lIAD9mt / zGlUfQ + JjFIiPvA + ZQBp
NWASGpwEHoHCMCERNb2spMiGGdf5lPB2LP76yDuSA / RcQA3CtAvgCE0AXFBfnEx / JLzDNpVN + OEH
RDKQomGH8ZM0NuzZmn79Hfc4YPup93UHasgv4QggaJHOn1EwiDfAQG9PJ / HYVl1QopWPXywz / U9S
rhfVhWVmAAfiHRe7oEgno + nUBx0EdXoiDg64EG / DBBsgg9aCDM6Oqmz0QfL8dEG6FBrs0iDwuvBB
7bTyRdep5XiYJve8Jn9x2GM6qbeJfw0cfXRFa2WDuk8 / cby9fjROB5FpqFykYm1PLvHxr9qmCrlQ
3MSgOa1zfHbyfH4DKpqUvbDard1K03Worpp08ulIiD8kBJ + xixlpbofFrr5GvR995mAmIg7LlEQa
3spgCDg7 + CD + JEG9DhQQdgIPiwQfIQIPnbrfHZznOc5znOc5znOcg5ByDkHIOQcg5ByDkHIOQcg5
ByDkHIOQcg5ByDkHIOQcg5ByDKpKpKpKpKpogBBm6P8NdyPJefd6HrvsfT2 / rcLO5bK + Fd / 6 + LKK
KpzXN8vf85ofW7rtf77ynFU + GBH + cLn4VHj6WRcDVAg1NyoDLWqA / xzf0dnh9zw9DlqpVTZe1pvE
mKqfhKA + тереть + LOQedMIYxhoxjAYgxJdnGCsYxiMlmDFioJrGMFNUUZYxeY8t57CYorx1nOCppIkm
KIiigqy4cTFFNUzWc5LLuin9UAB + PfrIJy6Pr + eJnNDmJ6W2MzCjO6nVR5IAKGIFqf5QCt0NykAp
yABANmbqCWA9SHG3q / fyKs8ArifkXP + VZ0r6UUrSp1SWcynqM3JfGGb + TCzdL5gKXUGufguANt9v
Ggo1uIp7qnq8YPU1TcaHnc60 / WXABx + o3NBl6vpnESB7Qe3arD7KR7GaKE0 / 6fCWKsuwc + gHKXeR
4VsFtjLcunY8sAnADS2SRNmAretAvcMkVr2Schn81VtvUD / snTAHjMfR7ALTtdjoLsSwiQDcVyUB
AkPgLWrSIdgKC8A5oVqH / dhxxcHj2dYznw2OcwKpyAXkyo8wkxm6GWybIiwjlYlJ8WGtsjSTLmfQ
YoltFrJy4WhtlrPd0fJ + 5RV7zyAmXXmQBz0Eb4IGo4j + HFyuxC5hmA + Lp7XGM6VBwKRtqmGZKoL8
Q + g1DSBrpMd / IFP + MvHBZ + JBE6kC6ANXFK2cfW8wgD0q5KxwFQVFWgB / mQaMAd56DKEBg3yHHvMD
hOJemYWGWffGSSokFQhNBj6gfMGpzy9QO7zQ5a8CFA98Mv0CgfzfuHIKdPp6gAPD8ABDIPxPP997
00/1 + 7Vf0M + oxq9jy5ThAnvnJmTj + 2OYOg5CZyJE8f + 3uXucXvDP9T + SDeO + ISnbL4bpVUABUYVL
7gXNX / LoTNp / Ym9nFudlNVYiRURymZRUkQUSLMrFBnwVWIkVPTq / 8u5U7jm / + IbMP2rfw3WSe55f
07XWWsziJFRHqfxqHNvwzZRVf3qVwc5C51vnWzfqnmasiQUz + G / fJRxMwp65aQcziraVQVB51ABt
gNsB7zG2DaA2gNsBtoG1BtQehOlzvA22DsB7TaByDxgdwHdyDsB1BgdQZoNUDbjTAzwZwM8GQG8A
zwaIN4Bmg6g7AcA4B0B1B0B0B2gdQcg5BwDug6g4B0B0BgdA25O0tgO3vA7gNEGgDRBkBogzwZ4N
MDNBmg + zPBlByDqDsB0B0B2wdNQdAdAcA7oPY7QOQfqNgOwGB2G9IbAd8HdB2wdgO0DgGeDOBxBT
g1IMp86u6Alr2mBsKcGoBlBpzpeXoGzgiImdM8ryUktMDWAzweZw + DqgayrvFO1YNiDUA7QPJ0Bg
yDv8AM8aHdnQHV2gddbaBtNAdm1zITAPADug7oOwHcBwDtA7AeODwA6g6g7AcA4B0B1B0B0B2gdQ
cg5BwDuA6g4B0B0BgdAdAdwHYDmyeDOBngyA0wM8GiDTA + / OBnAzwZAcA6g7AdAdAdwHUHIOQcA7
wOoOAdAdAYHQHQHeB2A7AdQdgOAd0HYD6HcB3gdgOwHaBwDgHQHYDoDoDtg6g5ByDgHdB1BwDoDo
DA6A6A8xTqUKCmvoqUFKKkilQpRUnqU6k1SapOUkUkUmKTVNpNUmqUVJyl / mKT5qminEU21MKaqd
tqphT + HYG / FV2rh21OMpUKUylBSipIpOUnKU6F9B / UDkrP6SW8gOEGEPQ6gHrR4h7AexQYQd3VOQ
Q5kCey9eYBCoBYBqCcoNtZ7 + lYPlQ5EZ0fwSB / St4j013Mj796pDwCEQBm0CAgEgpnKuxT6CMeKs
kFMsHy8JQdwgqxELgrIaSywjHJLQubX1C7AyKXGirdk5H946pfTw / XYoSR63vmvLksL76P1OwACB
hBDWusoCggvyACoQSAQYV7Cw4CBAImcuMkZG4aSZTgFkAAn5LcC + a1Wyqo9CCRnc + Rc3 + qLLLcNC
uZhQbgEGoxHOdhRL8F8 / liQxLf5kmp4qe / 33a2Ifbq / iyvacKwD3hAA7GIHX6MvCCKFUwFNBw1zw
cTvqiTlOP9KfzgEArnQBgcS4FPROW2ZdJoXbJGrzV5UeSjVBoAUD6v679RAg7XKhiQOmHHRc / VE2
HDegnENsOjHiz4yDYdb3eNY + IESh7XQgJDIrVA86uvicQoRfF0tFcwWrKLp7OoFr1ihsAblmMh4p
uIrW8exXq82p07OUnfw07QdCJDy2FaHZNmQRhcreIP2XUqHdfXen8krrwwQP9yOMxwVANQC / z1vJ
IEQQGcJdetX5q2ftJ2wM9Kj + rngQmC3PhSSAEmj874BadAqcp0TGT0FW1eKpIrD1rh6p / IJJG101
lx8bL5xf6gL89IEAI4IBCSWG3OiOaUqTo3bqCg7zKA73qrQ7zbC8hH + 97gcnxYaafW7KAkLqugCA
AOkUapcHf2jLhgHHedVmxgdas8utk5eurnq4DLQm5q9Zq9R4uy5ME3AwoQJ + 6RGRCECRkJYCAgIZ
WWAkJaBBhQamA5 / H9TiredrDtvtaCZhRb2knhxvtzJ8wLQHVS5nbSXjlMCAwURQ84JAOtPEFc5vL
tA3y2anUm4 + KCWSD6Ao8fRFuTr9 + d7V1SYFXxsFzbPofblVbcAo21b3u / UfU2qy6y6f54Hk0IOq6
л + 722ZguAaRAOw7vtUyqOshz1I8bzS2O29n0Xe2YHPQYcXgIPAQAGt7kG8x7K5JoQiaRM7VI0tLv
IzZtYzZutjNm1jMDkGByGtFc9ZAdQYHUGB2bNSpoyA6gwOoMDl0JIwA6AwOgMDnQoiKwA6AwOgMD
nSCrY5AdQYHUGB1dZijADoDA6AwOmjVMYVNFIUmKQpLMidOlIlZgpOU + XtLcv + Ro9X10bv9O23QX
7SXom0IIf3783F4pv39Hd5mApYbSLiSSEgXwO2Bh / X9Klcmc4s7ur8hIODmidLHN8l2Dzm17p770
нм / об / ZeD8VVVfAxiMRiMRiMRiMSOAYBwDAOAYBwDAOAYBwDAOAYBwDAOAYBwDAOAYBwDAOAYBwDC
mFIUwpEiHp5hzUO9MUV + evADDkP70VrEkDS4YAtctpD1 / JLDtsPG0gb / UlKiuB6Lor3bc4AayABK
2H6AIMv5AEGw2nTf19GskBAMPpNPm79DmTgiArc9l7a8F5Pn0kKRAg6tAEEgJwcU0AofWwmlBCog
aSYorSvhH0eTViKn + EVEcUjVghr6SMacICSGQegFn + errwXxHkzS2eAFY + kDmfhyVYaAHfOIWsON
2vIUbiBJz4GGp7J7ZmrAl + 8znekOADQSzQMmnd2djdZ2M42gxyWkpoS0Z / vz6iraIOyH / wgFImr9
HwOFslabdTMuJGdceuFXIz3k / HiqW5CEEzz + / 68Cx84flyhY57tPmrL3W6XTk + HBMuD4dNfyseDx
IEUgAJiBFRbZ6Ya4GTBJCu3aIgUNlzPNZMwD7e3doqIb0FU5NKLU36M1UcrY9Zasd000667DsA9O
2fezKtc0ACZ96QKVVd38AfCG + lH95C0jZTjIjz6LPCndEesoM8EAfJwBU3FtBf8LbLAs7jxvq8Tv
qoHj1Pae3itldbEtbHIcaQtA / T2gM7Xy / l2IIPrHIq0YFyTSFAEghN6EW32UGufZb2p5n770BUPd
gGLMAfmgBuHBIQ6QPrac9eHQrlo346lJmu412dxLYjEIJa27hVHQ5WBrsGxeZ6EW1JTf / Ds66sUn
LNwD3st9HUGCOrbltE3rSsVdTqt / 46l9lVHB9IcEhNC5jmbvWBY8 + rEt2c + Jz1c0fcK2A9FcYwTA
A33hM4C9W90n4jy9xX2gHpQRxa1Z1rQoRoUACz3TvKeTcgKk2UWvmRgkhruhdfJB1LFUmlBvONB +
ogvCBXwgvXE9OtwY00kuCfLAeAC2cHo3Sc7Wnhg3AN3 + ejuKl274 + XOx8kGQLf5 / PZW4YNShBAzn
ZvPOAUxyGtz0Xw7uwfqxzoni0IADC8UZcAGqKHfASyl0YOKxbQqmJ6qXPBKbgCBkbvJZe38D4TnS
EnhPRyyWUAAZhmLoo0RIFrpIKAeTvE4ZGApO7IHx8pmW4B0cIyysrDK9RK7ldiJ2xH + ZDOqZwrV5
IWgGf7BHacj / zjs8ZbVBy9AUjrtH9JP5V7NZBeS4AMLFxmnU / 8Pc5vhAGd2F5ye7J4uNqoBwjEtg
DyjMXm4fg1m / FN2ThVG0YUeHwfbViOzBSZFVGnmIt6cOggOX3cQ / XPHXWqW8EBV1hQYuqCtAef2q
5lDUA / хв + A4U ++ br2PUbhM0H3qP0gPAmWccEEjwi1 / j3N8RrT61o7DlIYADnWrl2vfanPXD + wVxc
AHX9CiUM7sTo7RMmFosktmAOVS900leEdROCR9iM7Zs50p6PyHffleg / IdqBEVdI78gAIEBcqbA6
FAMB + eJr253U7kbWK / дО + z3uLlW3WIGwx / + / + 6px9fuOCCh AL6daPfFXSr5Wvz2rr / c2cTW1uwRt
Gc7N2jfXIEC6LC8JHoQxn8UlslTC12NnCT7 / p84AcFqB74ViQ2B / NAOGsjL7wADq1Y1idU0gXzgJ
z88WoQzkNP8l1JN28Y0ueW4fW + 9OnI4BN1nsGYrVnP0EK0Du4DLYPxZ6 + H5IAbEsqbE / AAaflq3m
9v0nPc5TZKryWWwAqe0CQEPCBjwEFLClfLzMRDf7YJDSfdpIGNKxkMtxQz5mVUuH8nmz7sA7IKm3
q3zz6tTuHKxCLJjIbhWPoQw7RfzxvrXlyRV0ErIXEc3z5Nu142U1ZEhrdds99MbUNgDHyT3MIDTc
WTHq8NW7x1yYLqK2g5n2gCWIAVQkoB9Sd9R8ml0EHnCQpfuAgkVF7p + hcu2sGhA7UHFb / K54c7kH
JT2rtbgiECCaa7y7a3AtQ8x / YnegM1rOa3AEgILxcTuc8NXIGxKAcmgcqncSKFm0 + GVh34Ks4Ca6
mLKrDRkAdJE7fvjlTdyZd6IZeFjoMBUr0Oss8GZIEA8JAX15gXYBSulrshIayPQtWZJwK94rAkiA
Nvf3mmAvGj + 2MK + I1rAkorUZmznVe7sM7WTagTq8TvPdsJyJVh2sWSQmeunSj + i4dOY2YDXzsRBY
H6cxvacIkQXGZKDpUABP8UcNslpUMFyWYINks4Ais3c7LfRktkuLU0SAM + ghrSZPZanGAPMBE + Привет
QzPqo1s6rtlvFSGZlBGUAXB2B60DBoBjeP / vQgJa5eDI + 1T62TF / 7V0mY39eHq8fr17sAovGM3EV
p22sGHrTr8poMFo9rlh / ekPpVtgDqcIkmx4AD647TveT4tgtIJd2RoIIYliGIUPWwPloB9vIeqgf
CW8 / AHwYBCsMtKPj4Q3YA1nsoFDkynvLIdBCq + 3j8iPGQAUCPgQqQBEVeYvbBQQdaLoAUiXpA06D
iU1wwBubeq + awjNNYAf656ARWVRVg2yabvpLxuu8n / 0m6PRdwus5QSfuMQDn9jvw8JQthjErS5AO
4 + lodu6lZ9t1fwXjTfZTx855NErDYAuLtSqJlQ2sWDiuttyP8zoxnrf4xtV + XLA / dKJXjYjA0q2t
41b0lD9 + Qk0 / iefL3GlEkAqkJFBsxOdndROfSLc5CczexkbfYo / qReS1WrbuyAHQB / Cr72MFRKrK
eZ21Cj22nfpw27rIBTJaAHU8e3azXR3SvGMvWvcZcAgHNdyu2shZN4zZOf3h6 / rlEPSuSEw + IEog
pci7XfcxtvD2oORT / к / YLQ / Cq7nu1pvh4xIZNAdgG0H0ubtGvpfo8bOEPr72fBeuzS4G7jMAcwWF
27ALsMvbKdiYk758z1fhZ2tpE582oakBCDQpYLb2f9aaIVde2s07g / YmQ7K / 4hMXjjv / vydgAAHQ
so9Qndo / gHfAMfN4bq559ZJvb9uXqspwG9t85m88P5 + Rr4aOSdOAgVlikVHyd2Ti3HmKBi / MqaDV
sL1wnAE / ugR4gKqO / JC8W22Jze5spAZvgZQABAHIQmjKk5GtKIji7fxd1TQdaKuPNiFUFWJS65ED
L8z9yBQjcAwxBBYEEAsH4A2Pyua7maKaRlLL19G3fKeTethH7eWqznAFAdIQSJG4csaHOYnnS / OX
OOHLz8lZFKrC0uU3JBd6GNU6sAhYHhEwgm3AHBDEV3azVaxnDsmWxXKeZ66gYHfVOQvAAfnmKdAA
BIEPC8QQIyeprt8vV1H5c5vaVWRPLOCM3l6atqSeFYOWBegAvIdAGgntK2Uj5vwFD4VlJKRlVC0J
z7nP3MFqAVT7rRek8F / Zy / 7AZCE1Mrg2UBFgb3MwWGPk5njynv4mSpr8zgQJVAA5f2WelIGtynR4
eJZ7SHrvi9vVrAGyAhaHV1CaAlNhwXdaqGcgCRBIub9r50A4P453oWfa3 / f1novK3rrL0cO4g3SK
AF + J5ll / sWAnU9Qg + 7GsMugb1ndCCCgnUIOCxgAps78HV6c2X8Pd5fpr99Tvf99P7ZH36B82eSfM
zPMVDxYTi4TULbd9 + HWsQBk0FnkMj7sKQBqbHS8W2fZvLjn9dn2ne1C8G8udbkfmv4OO1Hv / zKzf
Вт / 4AYYDnjbtA5BuaCPj + 2deggY + 4fpvWkp / 7SWnnYjYdHgsPzmsdvs2BQGr3 / iVIjIZqXj5dxXoc
QxEggGx2rMV7F88Te7m62r2tH5M7Oqu1 / VivenvOV7fciH0WjqZr5PVHvRXfy / olOD8Vzpv8KmJJ
GVj2z9btv797opNtz / ++ ljzO6sve + 7v7PIf3X + ZWH / 490QCcPwaLh2wUq6aAI15GitK8xY / VBAmD
Y4wECM2NzkWYHL1PCtuLlm + KZ0fN2uW2X8QbS7RlG / 1hWL7ZKPCigVz + ow7W1exUYkkdhiNj1rhS
6aPGP03 + 8vp81Tydlr9vBVV3dtdNQeC9a7swGT7LHEKLnz6TbcjF6 + sEDIrebWc6 + symQJF8 + 0DA
KIQE9316H0UJ3jfRil5W0zvf / m96XYOGW5m + RA8DZsIaS1NVa8 / qbc03xlIbFgaf8czo6TwZy4Qq
6oXJBwkckTuv3j + TEAfx2s2lorR9max28vusi + х + UFAWnWPsdzOw5p6pTVKjx + FrlFxff + 0 / W8Z2
Pfx + LO5 / jvwnM3Ej6fonL / tG9Jb5lthrAMgMbgqyDfUELd7f73lQZ + kBSgP + 5d58WT9mRlNjT2vN
/ K96yv + uCy2PxPsoZa1Qdn4X + deSU7Mn1VyW9ymSQKfkeYaeSFbQQKvLHS8ezgjOE31LchHRplOT
7nwrrfv / VQ6Cevfo + 9LEdvZfx0PjiVPWsMq3S0cR9sC5ulgk4 / NXKv4aNFQ8 + z6Wja74nE4aVJGN
Hax + pB0f8 / CranGLVF51Dbk9HG / bYcCo2Yk9bMrOGN6uh7hZNvCgkCJAEdUbMrNL3sh / YGOpv5I5
RL6cXmOAqaCWoDU7jrXfDDSWkkHmkoPI2H0TFz3N + ooK6ez89y49HZqWWzn / prn7z29WzUMpP87P
dR1vh97fLrzLn8QJe + FggQcJyeQOqBBoH5zrPAnmGE3UVGwbVa6 / OAT / wImAcgKDCXq4 / vZJLZ8C
О / 7L3zaNrYvjeRX7FlrJVvRe46TEw9oJm92C15gE5MLfFg4MgSJIqsL85CjaswBXvKP6gf8DQjpb
7bohufI7 / Lfve / V68Rt59Vw6Ccwklrdt3fWv4U9Ieqm + 6TBAt4H6i12qZuCaoPl01QZoD7VYqZSO
qqsZxhuB14YOQ2TqJDxrIupeT4ezp / e96svnMfH4HSdX3WTqPRTyrIkgdE / xfn3mdk3FEiamcZz +
aN4bEDzY8kLcViBKY0ADNEfO0FMDk3s + lVIqehPUL9zsT + 7fOu / szXSwUQiJiwSF6XxxN + zGIqIh
б / 2eZF1JSQHRInCCL8Kx0wCBSFH4kIOVRkINIwSrZp9MLEur90Z / СУГ + FIfX25SLhuiTEUsxgSBC
W8u7Vyoa5oyOt47 / 9LW1jCRvAt9QHWIFoA4hPiHxKjYD4RKsZYYCEix / 7v4jmv / Банк Японии + w73wg17ei
UfWmS9Gym1Mvk6DIVAAA2dVFlODLKZ7CKFV2XZd8JfU3aSJdOX / 7CXC82dxOaGh4 / t2OkzHr1feY
3uchvA0E3hbXh / e9xL5f1NrmhDcAdYFaN3xjnWcGtPmboVrR + 425TFUK90qF50vGqFIQ8vB23tgr
кк + BmYDp8XppnmIAFVtly8H9CdxfBVdKDAfpCHsxgOg8r + s7TmgnFB4khuezp8eGRNAbDeBYM3k +
S0tX6iPW1vuU6PkPBhiN6ZbuWqEi5r8EgQxRdSMDrm2C2wJ35ItBOIAwgNYAwhzwCnjFYaYLe4zo
hUtVOw + SabSJGRo5RqKoG1ur7sug33u7uA6fT6D2EgmX863NQOqpYgC7iC1XuSDmQ8ejtoHUz7Xj
+ WAwK2VU4shsdl8KjrAD3Ec / x4iIhh6cfC / Ux8CaDwWCCEZNWAhBRwF2aHZQhCA / mrFo + Vn / Qvbg
cEblqZlCXbDMb60IqgnNJUAjFwAQhCHd9gYGJYuGvqlApR6hSmG4n1IQIfSXftZLPZhCwOdMJARs
b2u4hFb2ggZGvjM / hJSUNI / 3 / f6ycRymgi4X / ка / HWKpUDqAw / J / jx7eXc76q1P2DLJI8S / а / nV6
S5Ud56prWfrixl + o6wtGlyvkOqos1oPAECxSyM5KaMCjlLFIDx + ej59Fkdf8jAjUZvw / yBT6ygvL
oeLO214jL3sfoifigCAfaz2OsowBeZ + RF2 + 6nkyfF09j90 + bpttxO3Hx14I5ct4Q9jH93j + nVR2g
hEAxAMQqkMKV / kWXwzc77t52KJz2q1zmq1S4G1x69Kz + оА / QU4AB / 2y1xh6PhsZtoWaHyDu0S5IQ
aSh8LeP31 + wIGbyOZVPkM2n / YjAUNv2bEHXhYHIFvQT9yf8RCXZd4vl6ASrnKLI + d2qYnNrUW1Ng
NlAj0rf5VkhJxFSCanG + iIcyyqL4qX9xHgAA + mluM1rrwAtLkkd1ofd87lZem + qk1KEb5dpDbi7q
hgDK2LduIJ5owSR57uIuyP6wkaW2JAprdq9w9EpFoUeSbl7a7F9PjWsiBmAgY3r3ePVBlVEoMPe3
O9cQdd6PWGEBoO37at + 5dF + QAGt09ODv53V / e5D1ECNjYVlx / з + FB3 + yrXxFKOWJJzXMe / Qtqhjg
IljLH0OeH6nbW3U5Tf78Q0uY6rxzGXG + F8C0K4a + E4nmxVxbwit7QEFOk2lfszEG + ggIIlbcPP6G
S / 84Fp8AMwakQn2JjdgACpWYA7bjIRrLGtDkL0EC / wzdu + ttg9GUvl3BuQv7OJHS9NQBw + YEEKV0
BXkDbI36AKvsHLP1g1 / iP8aSBr8podjCY2fuLHnOOX4sthQSSyUwlC97ntxmDg28dRtbzRuQ0wP8
3V62hO9nc7X9fb9fznzhRBNYF5IFEEjJQBIKIJmK7I8Xh5Pn9xywJX7HKInI9jqQQbwACgmCD1RR
BPBFEE // F3JFOFCQsfyJNg ==
«»»
печать ([ '', 'Up', 'вниз'] [Int (pickle.loads (bz2.decompress (base64.b64decode (s))). предсказать (numpy.array ([skimage.transform.resize (skimage.io .imread (sys.argv [1], as_grey = True), (24,12), режим = 'константа'). сплющить ()])) [0])] + 'козу')

обновление: для каждого запроса приведены данные обучения, размер которых увеличен до 24x12 и объединен в одно изображение для удобства загрузки / презентации. его более ста изображений. http://deeplearning.net/datasets/ , http://www.vision.caltech.edu/Image_Datasets/Caltech256/ , поиск изображений duckduckgo, поиск изображений в Google и т. д.

тренировочные данные в 24x12 пикселей

не яркий
источник
Можете ли вы опубликовать данные о тренировках?
Qwr
некоторые из точных исходных изображений, которые я использовал, защищены авторским правом, поэтому я не могу опубликовать их все, однако я сократил кучу их до размера, используемого в системе, 24x12, и разместил их на одном изображении выше, которое следует квалифицировать как ' добросовестное использование'.
Дон Яркий
6

Scikit-Learn со случайными лесами, 100%

Испытанный и верный подход - это коннет, но случайные леса могут работать очень хорошо из коробки (несколько параметров для настройки). Здесь я показываю некоторые общие методы в задачах классификации изображений.

Я начал с 100 изображений коз для обучения, которые я нашел через Google Images (AFAIK ни один в данных обучения не соответствует данным теста). Каждое изображение масштабируется до 20x16 в оттенках серого, затем массив выравнивается, чтобы создать одну строку в двумерном массиве. Перевернутая версия изображения также добавляется в виде строки для обучающих данных. Мне не нужно было использовать какие-либо методы увеличения данных .

сетка коз

Затем я передаю двумерный массив в классификатор случайных лесов и вызываю предикат, чтобы получить 50 деревьев решений. Вот (грязный) код:

RESIZE_WIDTH = 20
RESIZE_HEIGHT = 16

def preprocess_img(path):
    img = cv2.imread(path, 0)  # Grayscale
    resized_img = cv2.resize(img, (RESIZE_WIDTH, RESIZE_HEIGHT))
    return resized_img


def train_random_forest(downgoat_paths, upgoat_paths, data_paths):
    assert len(data_paths) == 100
    # Create blank image grid
    img_grid = np.zeros((10*RESIZE_HEIGHT, 10*RESIZE_WIDTH), np.uint8)

    # Training data
    TRAINING_EXAMPLES = 2*len(data_paths)
    train_X = np.zeros((TRAINING_EXAMPLES, RESIZE_WIDTH*RESIZE_HEIGHT), np.uint8)
    train_y = np.zeros(TRAINING_EXAMPLES, np.uint8)

    TEST_EXAMPLES = len(downgoat_paths) + len(upgoat_paths)
    test_X = np.zeros((TEST_EXAMPLES, RESIZE_WIDTH*RESIZE_HEIGHT), np.uint8)
    test_y = np.zeros(TEST_EXAMPLES, np.uint8)


    for i, data_path in enumerate(data_paths):
        img = preprocess_img(data_path)

        # Paste to grid
        ph = (i//10) * RESIZE_HEIGHT
        pw = (i%10) * RESIZE_WIDTH
        img_grid[ph:ph+RESIZE_HEIGHT, pw:pw+RESIZE_WIDTH] = img
        flipped_img = np.flip(img, 0)

        # Add to train array
        train_X[2*i,], train_y[2*i] = img.flatten(), 1
        train_X[2*i+1,], train_y[2*i+1] = flipped_img.flatten(), 0

    cv2.imwrite("grid.jpg", img_grid)

    clf = RandomForestClassifier(n_estimators=50, verbose=1)
    clf.fit(train_X, train_y)
    joblib.dump(clf, 'clf.pkl')

    for i, img_path in enumerate(downgoat_paths + upgoat_paths):
        test_X[i,] = preprocess_img(img_path).flatten()
        test_y[i] = (i >= len(downgoat_paths))


    predict_y = clf.predict(test_X)
    print(predict_y)
    print(test_y)
    print(accuracy_score(predict_y, test_y))

    # Draw tree 0
    tree.export_graphviz(clf.estimators_[0], out_file="tree.dot", filled=True)
    os.system('dot -Tpng tree.dot -o tree.png')


def main():
    downgoat_paths = ["downgoat" + str(i) + ".jpg" for i in range(1, 10)]
    upgoat_paths = ["upgoat" + str(i) + ".jpg" for i in range(1, 10)]
    data_paths = ["data/" + file for file in os.listdir("data")]

    train_random_forest(downgoat_paths, upgoat_paths, data_paths)

Вот первое дерево решений (хотя, поскольку модель находится в ансамбле, она не особенно полезна )

дерево решений № 0

qwr
источник
это очень интересно .... ваши тренировочные данные кажутся намного более разнообразными типами картинок, чем мои.
Дон Брайт
@donbright Я бы опубликовал свои тренировочные данные, но папка со всеми моими фотографиями была на жестком диске, который умер. Если кто-то достаточно амбициозен, он может использовать обратный поиск картинок Google и найти фотографии, которые я использовал.
qwr
это классно. Я скачал кучу изображений, но потратил огромное количество времени на их сортировку для «чистых» изображений. Интересно посмотреть, как можно тренироваться, основываясь на более «грязных» изображениях, не тратя при этом как можно больше времени на сортировку.
Дон
@donbright Я считаю, что больше тренировочных данных и разнообразия лучше. Для «чистых» и «грязных» мы можем использовать увеличение данных, чтобы создать «больше данных».
qwr