Квадрат, коло, трикутник,… Шестірня?


69

Використовуючи Algodoo та Paint, я зробив ці шість однотонних зображень 300 × 300 чотирьох зручних форм:

Зображення 1 Зображення 2 Зображення 3 Зображення 4 Зображення 5 Зображення 6

Цей клас зображень має такі властивості:

  • Вони завжди розміром 300 × 300 пікселів, однотонні (лише чорно-білі) і мають рівно чотири білі області, які відповідають квадрату, колу, трикутнику та передачі.
  • Форми ніколи не перетинаються і не торкаються один одного, а також не торкаються межі зображення і не виходять за межі.
  • Форми завжди мають однаковий розмір, але їх можна обертати і розміщувати будь-яким способом.

(Форми також мають рівні площі, хоча при такому зростанні їх кількість пікселів навряд чи буде рівнозначною.)

Виклик

Напишіть найкоротшу можливу програму або функцію, яка приймає назву файлу такого зображення і перетворює всі білі пікселі ...

  • червоний, (255, 0, 0)якщо вони на площі.
  • синій, (0, 0, 255)якщо вони в колі.
  • зелені, (0, 255, 0)якщо вони в трикутнику.
  • жовтий, (255, 255, 0)якщо вони знаходяться в передачі.

напр

Зображення 1 кольорове в

Деталі

Ваша програма повинна ефективно працювати з усіма можливими вхідними зображеннями. (Буде введено лише дійсні 300 × 300 монохроматичних зображень.) Шість наданих мною зображень - лише приклади, ви не можете жорстко кодувати їх вихід у вашу програму.

Ви не можете використовувати бібліотеки чи функції комп'ютерного зору, вбудовані або зовнішні. Сенс у тому, щоб зробити це за допомогою власних операцій на рівні пікселів. Ви можете використовувати бібліотеки зображень, які просто дозволяють відкривати та змінювати зображення (наприклад, PIL для Python).

Ви можете використовувати будь-які загальні формати файлів зображень без втрат для введення та виведення, доки дотримуєтесь колірної схеми.

Ви можете взяти назву файлу зображення як аргумент функції, з stdin або з командного рядка. Вихідне зображення можна зберегти у новий файл, той самий файл або просто відобразити.

Оцінка балів

Виграє подання з найменшими байтами . Я можу перевірити матеріали з додатковими зображеннями, щоб визначити їх валідність.


Чи можемо ми припустити, що введення чорно-біле, без анти-згладжування? Якщо ні, то чи можемо ми видалити анти-згладжування з анти-псевдонімів?
Джон Дворак

@JanDvorak Так. Під монохроматикою я маю на увазі лише чорне і біле, тому не може бути згладжування.
Захоплення Кальвіна

1
Може нам потрібен конкретний формат введення точніше, ніж просто розширення файлу? А саме, я хотів би, щоб я вводив ASCII PBM без будь-яких коментарів.
Іван Дворак

12
Отже ... Я намагався вирішити це, і я закінчився цим образом . Не дуже впевнений, як, але ей, це виглядає химерно. : P
Дверна ручка

2
Я не хочу розміщувати своє рішення, оскільки це та сама ідея, що і Елла, але гірша. Але я просто хочу сказати, що це було приємним маленьким завданням :)
Кріс Берт-Браун

Відповіді:


8

J - 246 224 185 байт

load'viewmat'
(viewmat~0,(255*4 3$_2|.#:3720)/:/:@(<([:}.(>./%+/%#)@:(+/&:*:@(-"1)+/%#)@(4$.$.@:=)&>)<"0@~.@,))@(~.@,i.])@(>./**@{.)@((0,(,-)#:>:i.3)&|.)^:_@(*i.@:$)@(0<readimg_jqtide_)

Це було весело!

Я повторно використав частину з підключеними компонентами, яку я використав для завдання "Я в найбільшій кімнаті" , і використав співвідношення між середньою та максимальною відстані всіх точок до центру кожного компонента. Я вирішив це, оскільки це і масштаб, і обертання інваріантно, і, очевидно, досить добре, щоб розрізнити фігури, як задано. Рейтинг цього значення від низького до високого дає мені порядок кола, шестірні, квадрата та трикутника, які використовуються для перестановки кольорової карти.

Відображає результат, використовуючи аддон відображення карти. Не використовуються панелі інструментів, крім читання та виводу файлів.

Міцність, здається, не є вимогою, це займає 18 байт. 2 більше непотрібні простору, замінені &.>на &>в ratioі &.:на &:в dcent ще 2 байта.

Величезний приріст як в короткості, так і в продуктивності compвикористання зсуву замість cut( ;.). Таким чином зображення відтворюється та зміщується у всіх 8 напрямках замість того, щоб сканувати його за допомогою вікна 3x3.

idФункція була до смішного складної для того, що це потрібно робити. Тепер він призначає ідентифікатори пікселям в об'єктах шляхом множення зображення на масив унікальних чисел, отже, встановлюючи значення BG в нуль.

Код трохи більше пояснено:

load'viewmat'                                 NB. display only
imnames =: < ;. _2 (0 : 0)
C6IKR.png
DLM3y.png
F1ZDM.png
Oa2O1.png
YZfc6.png
chJFi.png
)

images =: (0<readimg_jqtide_) each imnames    NB. read all images in boxed array

id =: *i.@:$                                  NB. NB. assign one number to each non-background (non-zero) pixel
comp =: (>./ * *@{.)@shift^:_@id              NB. 8 connected neighbor using shift
  shift =: (>,{,~<0 _1 1)&|.                  NB. generate the original, and 8 shifted versions (automatically padding and cropping).
result =: comp each images                    NB. Execute comp verb for each image
col =: (~.@, i. ])                            NB. Color: give each component and BG a separate color.

NB. BG in 0, 0 Get all max distance to center % mean distance to center ratios
ratio  =: (< ([:}.rat@:dcent@getInd &>)  <"0@~.@,)
  getInd =: 4 $. $.@:=                        NB. get indices for component y in array x
  dcent  =: +/&.:*:@(-"1) +/%#                NB. distence from center each point
  rat    =: >./ % +/%#                        NB. ratio from distances

cm=: (255*4 3$_2|.#:3720)                     NB. colormap (except black).
(viewmat~ 0,cm /: /:@ratio )@col each result  NB. for each image, show the result, permuting the colormap according to ratio's

NB. almostgolf this
P1 =: (>./**@{.)@((0,(,-)#:>:i.3)&|.)^:_@(*i.@:$)@(0<readimg_jqtide_) NB. reading till components
P2 =: (<([:}.(>./%+/%#)@:(+/&:*:@(-"1)+/%#)@(4$.$.@:=)&>)<"0@~.@,) NB. recognition: get fraction mean vs max distance to center per component, toss BG.     
P3 =: (viewmat~0,(255*4 3$_2|.#:3720)/:/:@P2)@(~.@,i.])@P1    NB. piece together : permute colormap, display components

NB. seriousgolf
load'viewmat'
f =:(viewmat~0,(255*4 3$_2|.#:3720)/:/:@(<([:}.(>./%+/%#)@:(+/&:*:@(-"1)+/%#)@(4$.$.@:=)&>)<"0@~.@,))@(~.@,i.])@((>./**@{.)@shift^:_)@(*i.@:$)@(0<readimg_jqtide_)
NB. example usage:
f&> imnames NB. do for all images

Це трохи довго, щоб детально пояснити, але зробимо, якщо є інтерес.


Правий верхній піксель гарантовано становить bg. Згідно з ОП "Форми ніколи не перетинаються і не торкаються одна одну, а також не торкаються межі зображення і не виходять за межі".
Доктор Белісарій

Дякую, це корисно. (власне, я мав на увазі лівий верхній піксель, перший у равелі). Це знищує виявлення фону (22 байти).
jpjacobs

Різко скоротилася довжина і збільшилася продуктивність :)
jpjacobs

29

Математика, 459 392 байт

f=(d=ImageData@Import@#/.{a_,_,_}:>a;(For[a={};b={#&@@d~Position~1},b!={},c=#&@@b;b=Rest@b;d[[##&@@c]]=0;a~AppendTo~c;If[Extract[d,c+#]==1,b=b⋃{c+#}]&/@{e={1,0},-e,e={0,1},-e}];m=1.Mean@a;m=#-m&/@a;n=Count[Partition[Norm/@SortBy[m,ArcTan@@#&],300,1,1],l_/;l[[150]]==Max@l];(d[[##&@@#]]=Round[n^.68])&/@a)&/@Range@4;Image[d/.n_Integer:>{{0,0,0},,{0,1,0},{1,0,0},,,,{1,1,0},{0,0,1}}[[n+1]]])&

Безголівки:

f = (
 d = ImageData@Import@# /. {a_, _, _} :> a;
 (
    For[a = {}; b = {# & @@ d~Position~1},
     b != {},
     c = # & @@ b;
     b = Rest@b;
     d[[## & @@ c]] = 0;
     a~AppendTo~c;
     If[Extract[d, c + #] == 1, 
        b = b ⋃ {c + #}] & /@ {e = {1, 0}, -e, e = {0, 1}, -e}
     ];
    m = 1. Mean@a; m = # - m & /@ a;
    n = 
     Count[Partition[Norm /@ SortBy[m, ArcTan @@ # &], 300, 1, 1], 
      l_ /; l[[150]] == Max@l];
    (d[[## & @@ #]] = Round[n^.68]) & /@ a
    ) & /@ Range@4;
 Image[d /. 
   n_Integer :> {{0, 0, 0}, , {0, 1, 0}, {1, 0, 0}, , , , {1, 1, 
       0}, {0, 0, 1}}[[n + 1]]]
) &

Я міг би зберегти ще 6 байт, перетворившись m=1.Mean@a;m=#-m&/@a;на це m=#-Mean@a&/@a;, але це значно підірває час виконання, що дратує тестування. (Зауважте, що це дві оптимізації: виведення обчислення з Mean@aциклу та використання точних символьних типів замість чисел з плаваючою точкою. Цікаво, що використання точних типів набагато важливіше, ніж обчислення середнього значення в кожній ітерації.)

Отже, це підхід номер три:

  • Визначте ділянки за допомогою заливної заливи.
  • Знайдіть приблизний центр кожної області шляхом усереднення всіх піксельних координат.
  • Тепер для всіх пікселів у формі давайте побудуємо відстань від кута до цього центру:

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

    Трикутник має 3 чіткі максимуми, квадрат 4, шестірня 16, а коло має тони, через зменшення коливань щодо постійного радіуса.

  • Ми знаходимо кількість максимумів, дивлячись на фрагменти 300 пікселів (упорядковані за кутом), і підраховуємо фрагменти, де піксель у положенні 150є максимумом.
  • Тоді ми просто розфарбовуємо всі пікселі залежно від кількості піків (коло - це все, що перевищує 16, і, як правило, дає близько 20 піків, через розмір фрагментів).

Тільки для запису, якщо я використовую ідею Ell і просто сортую регіони за найбільшою відстані між будь-яким пікселем та центром, я можу це зробити у 342 байтах:

f=(d=ImageData@Import@#/.{a_,_,_}:>a;MapIndexed[(d[[##&@@#]]=#&@@#2)&,SortBy[(For[a={};b={#&@@d~Position~1},b!={},c=#&@@b;b=Rest@b;d[[##&@@c]]=0;a~AppendTo~c;If[Extract[d,c+#]==1,b=b⋃{c+#}]&/@{e={1,0},-e,e={0,1},-e}];a)&/@Range@4,(m=Mean@#;Max[1.Norm[#-m]&/@#])&],{2}];Image[d/.n_Integer:>{{0,0,0},{0,0,1},{1,1,0},{1,0,0},{0,1,0}}[[n+1]]])&

Але я не маю наміру конкурувати з цим, якщо всі інші використовують свої власні оригінальні алгоритми, а не гольфують інші.


Найцікавіше рішення!
CSharpie

25

Ява, 1204 1132 1087 1076

Просто довести собі, що я можу це зробити.

Я включив імпорт поруч із деклараціями про функції; вони повинні бути поза класом, щоб це працювало:

import java.awt.*;import java.awt.image.*;import java.io.*;import java.util.*;import javax.imageio.*;

BufferedImage i;Set<Point>Q;void p(String a)throws Exception{i=new BufferedImage(302,302,1);i.getGraphics().drawImage(ImageIO.read(new File(a)),1,1,null);Set<Set<Point>>S=new HashSet<>();for(int y=0;y<300;y++){for(int x=0;x<300;x++){if(!G(x,y)){Point p=new Point(x,y);Q=new HashSet<>();if(!S.stream().anyMatch(s->s.contains(p)))S.add(f(x,y));}}}Object[]o=S.stream().sorted((p,P)->c(p)-c(P)).toArray();s(o[0],255);s(o[1],255<<16);s(o[2],0xFF00);s(o[3],0xFFFF00);ImageIO.write(i.getSubimage(1,1,300,300),"png",new File(a));}boolean G(int x,int y){return i.getRGB(x,y)!=-1;}Set<Point>f(int x,int y){Point p=new Point(x,y);if(!Q.contains(p)&&!G(x,y)){Q.add(p);f(x-1,y);f(x+1,y);f(x,y-1);f(x,y+1);}return Q;}int c(Set<Point>s){return(int)s.stream().filter(p->G(p.x-2,p.y-1)||G(p.x-2,p.y+1)||G(p.x+1,p.y-2)||G(p.x-1,p.y-2)||G(p.x+2,p.y-1)||G(p.x+2,p.y+1)||G(p.x+1,p.y+2)||G(p.x-1,p.y+2)).count();}void s(Object o,int c){((Set<Point>)o).stream().forEach(p->{i.setRGB(p.x,p.y,c);});}

Необолочений (і працює, тобто додається котельня):

import java.awt.Point;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.HashSet;
import java.util.Set;
import javax.imageio.ImageIO;

public class SquareCircleTriangleGear {
    public static void main(String[]args){
        try {
            new SquareCircleTriangleGear().p("filepath");
        } catch (Exception ex) {
        }
    }
    BufferedImage i;
    Set<Point>Q;
    void p(String a)throws Exception{
        i = new BufferedImage(302,302,BufferedImage.TYPE_INT_RGB);
        i.getGraphics().drawImage(ImageIO.read(new File(a)),1,1,null);
        Set<Set<Point>>set=new HashSet<>();
        for(int y=0;y<300;y++){
            for(int x = 0;x<300;x++){
                if(i.getRGB(x,y)==-1){
                    Point p = new Point(x,y);
                    Q=new HashSet<>();
                    if(!set.stream().anyMatch((s)->s.contains(p))){
                        set.add(fill(x,y));
                    }
                }
            }
        }
        Object[]o=set.stream().sorted((p,P)->c(p)-c(P)).toArray();
        s(o[0],0x0000FF);
        s(o[1],0xFF0000);
        s(o[2],0x00FF00);
        s(o[3],0xFFFF00);
        ImageIO.write(i.getSubImage(1,1,300,300), "png", new File(a));
    }
    Set<Point>fill(int x, int y){
        Point p=new Point(x,y);
        if(!Q.contains(p)&&!i.getRGB(x,y)!=-1) {
        Q.add(p);
            fill(x-1,y);
            fill(x+1,y);
            fill(x,y-1);
            fill(x,y+1);
        }
        return Q;
    }
    int c(Set<Point>s){return (int)s.stream().filter(p->isBoundary(p.x,p.y)).count();}
    boolean isBoundary(int x, int y){
        return i.getRGB(x-2,y-1)!=-1||i.getRGB(x-2,y+1)!=-1||i.getRGB(x+1,y-2)!=-1||
               i.getRGB(x-1,y-2)!=-1||i.getRGB(x+2,y-1)!=-1||i.getRGB(x+2,y+1)!=-1||
               i.getRGB(x+1,y+2)!=-1||i.getRGB(x-1,y+2)!=-1;
    }
    void s(Object o,int c){
        ((Set<Point>)o).stream().forEach(p->{i.setRGB(p.x,p.y,c);});
    }
}

Це працює за допомогою ітерації над кожним пікселем зображення та заповненням заливів кожного разу, коли ми досягаємо "дірки". Додаємо кожен результат заливки як Set<Point>а Set. Потім ми визначаємо, яка форма, яка. Це робиться шляхом перегляду кількості граничних пікселів фігури. Я визначав межу як відступ лицаря від чорної плитки, оскільки це буде залишатися більш постійним між обертаннями та подібними. Коли ми це робимо, стає зрозуміло, що фігури можна сортувати за цим значенням: Коло, Квадрат, Трикутник, Шестірня. Тому я сортую і встановлюю всі пікселі такої форми до потрібного кольору.

Зауважте, що зображення, до якого я пишу, не береться безпосередньо з файлу, тому що якби я це зробив, Java ставилася б до зображення як до чорно-білого, а наповнення кольорами не працювало. Тому я маю створити власний образ за допомогою TYPE_INT_RGB(що є 1). Також зверніть увагу , що зображення , яке я роблю роботу на це 302шляхом 302; це так, що алгоритму дистанції Найт не потрібно турбуватися про спробу читання поза межами зображення. Цю невідповідність за розміром я виправляю за допомогою дзвінка i.getSubImage(1,1,300,300). Примітка. Можливо, я забув виправити це, коли завантажував зображення, у цих випадках зображення занадто широкі на 2 пікселі, але, крім цього факту, вони повинні бути правильними

Функція замінить файл, шлях якого передано. Виходи:

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


Можна зберегти кілька символів, скоротивши ім'я класу, а також аргументи в основному методі до "a" або подібного.
Райан

@Ryan Ці рахунки не враховуються. Я підраховую лише імпорт + функції, як це дозволяє питання.
Джастін

Я думаю, що мені це вдасться отримати під 1000 байтів. Треба попрацювати над цим пізніше, коли є час спробувати.
Джастін

20

Пітон, 571 567 528 байт

Аналогічно до рішення Квінкунса, він починається із заповнення кожної форми індексом від 1 до 4. Потім визначає тотожність фігур за радіусом їх граничного кола. Колірна палітра будується відповідно, і зображення зберігається як зображення в індексованому кольорі.

EDIT: Пропущений факт, форми гарантовано не торкаються межі зображення. Тоді коротше!

from PIL.Image import*;from numpy import*
I=open(sys.argv[1]).convert("P")
D=list(I.getdata())
W=300;R=range(W*W);N=range(5)
O=[[0,i,array([0,0])]for i in N];n=0
for i in R:
 if D[i]>4:
    n+=1;S=[i]
    while S:
     j=S.pop()
     if D[j]>4:D[j]=n;O[n][0]+=1;O[n][2]+=j%W,j/W;S+=[j+1,j-1,j+W,j-W]
for o in O[1:]:o[2]/=o[0];o[0]=0
for i in R:
 if D[i]:o=O[D[i]];v=(i%W,i/W)-o[2];o[0]=max(o[0],dot(v,v))
O.sort()
C=[0]*5+[255]*3+[0,255,0,0]*2;P=C[:]
for i in N:j=3*O[i][1];P[j:j+3]=C[3*i:3*i+3]
I.putdata(D);I.putpalette(P);I.save("o.png")

Приймає вхідне ім'я файлу в командному рядку і записує вихід у o.png.


2
Арг, це набагато простіше, ніж те, що я намагаюся зробити. +1
Мартін Ендер

7

Mathematica 225


Оновлення :

ОП вирішило, що цей підхід використовує функції комп’ютерного зору, тому він більше не працює. Я залишу це повідомлення однак. Можливо, хтось може виявити це цікавим.


f@i_ := (m = MorphologicalComponents[ImageData@i];
Image@Partition[Flatten[(m)] /. 
   Append[ ReplacePart[SortBy[ComponentMeasurements[m, "Circularity"], Last], 
   {{1, 2} -> Yellow, {2, 2} -> Green, {3, 2} -> Red, {4, 2} -> Blue}], 0 -> Black], 
Dimensions[m][[2]]])

ImageData повертає зображення у вигляді матриці 0 і 1.

Flatten перетворює цю матрицю в список.

Morphological Componentsзнаходить 4 кластери пікселів і присвоює окреме ціле число, 1, 2, 3, 4 кожному пікселю відповідно до кластеру. 0 зарезервовано для (чорного) фону.

ComponentMeasurements перевіряє круговість кластерів.

Завжди від найменшого до кругового завжди будуть: коло, квадрат, трикутник і шестірня.

ReplacePart замінює кожне ціле число компонентів відповідним кольором RGB, використовуючи сортування кругової форми.

Partition...Dimensions[m][[2]] приймає список кольорів пікселів і повертає матриці ті ж розміри, що і вхідне зображення.

Image перетворює матрицю кольорів пікселів у кольорове зображення.

входи

{f[img1],f[img2],f[img3],f[img4]}

виходи


147 символів:f@i_:=Image[#/.Append[Thread[Ordering[Last/@ComponentMeasurements[#,"Circularity"]]->{Yellow,Green,Red,Blue}],0->Black]]&@MorphologicalComponents@i
алефальфа

Незначна точка: у ваших кольорах немає правильних значень rgb. Основний момент: Я не впевнений, що вважаю це тим, що не використовую бібліотеки чи функції комп'ютерного зору.
Захоплення Кальвіна

"Циркулярність", мабуть, візуальна; Я побачу, що ще можу зробити. Однак кольори мертві: {RGBColor[1, 0, 0], RGBColor[0, 1, 0], RGBColor[0, 0, 1], RGBColor[1, 1, 0]}там, де 1 відповідає 255. Жодна бібліотека не використовувалася.
DavidC

@ Calvin'sHobbies Проблема, схоже, зводиться до того, MorphologicalComponentsзадовольняє чи порушує правила. Як тільки ви дізнаєтесь, до якого кластеру належить кожен піксель, існує багато способів, включаючи кількість необроблених пікселів, щоб визначити, яка цифра є.
DavidC

Я хочу сказати, що це порушує правила, оскільки це, мабуть, функція комп’ютерного зору, і це надає Mathematica несправедливу перевагу. Я погоджуюся, що кольори повинні бути правильними, але вони чітко виглядають на вашому зображенні (червоний - це (255,0,22)коли я зареєструюсь у Paint). У мене немає Mathematica, тому я не можу бігти, щоб переконатися.
Захоплення Кальвіна

7

Математика, 354 345 314 291 288

І все-таки гольф може бути скорочений ще на кілька символів, але продуктивність стає нестерпною. Використовує Варіант для ідентифікації фігур:

f=(w=Position[z=ImageData@Import@#,1];r=Nearest;v@x_:=Variance@N[Norm[Mean@x-#]&/@x];Image[Plus@@(ReplacePart[0z/. 0->{0,0,0},#->r[{108,124,196,115}->List@@@{Blue,Red,Green,Yellow},v@#][[1]]]&/@Rest@NestList[(m=r[w=w~Complement~#];FixedPoint[Union@@(m[#,{8,2}]&/@#)&,{#&@@w}])&,{},4])])&

З інтервалом:

f = (w = Position[z = ImageData@Import@#, 1];
     r = Nearest; 
     v@x_ := Variance@N[Norm[Mean@x - #] & /@ x];
     Image[Plus @@ (ReplacePart[ 0 z /. 0 -> {0, 0, 0}, # -> r[{108, 124, 196, 115} -> 
                                              List @@@ {Blue, Red, Green, Yellow}, v@#][[1]]] & /@
     Rest@NestList[(m = r[w = w~ Complement~#];
                   FixedPoint[Union @@ (m[#, {8, 2}] & /@ #) &, {# & @@ w}]) &
                   , {}, 4])]) &

Тестування:

s = {"http://i.stack.imgur.com/Oa2O1.png", "http://i.stack.imgur.com/C6IKR.png", 
     "http://i.stack.imgur.com/YZfc6.png", "http://i.stack.imgur.com/F1ZDM.png", 
     "http://i.stack.imgur.com/chJFi.png", "http://i.stack.imgur.com/DLM3y.png"};
Partition[f /@ s, 3] // Grid

Графіка математики

Тут він зовсім невольф. Пізніше додамо пояснення:

findOneZone[{universe_List, lastZone_List}] :=
 Module[{newUniverse, proximityFindFunc, seedElement},
  newUniverse = Complement[universe, lastZone];
  proximityFindFunc = Nearest@newUniverse;
  seedElement = {First@newUniverse};
  {newUniverse, FixedPoint[Union @@ (proximityFindFunc[#, {8, 2}] & /@ #) &, seedElement]}]

colorAssign[zone_List] :=
 Module[{
   vlist = {108, 124, 196, 115},
   cols = List @@@ {Blue, Red, Green, Yellow},
   centerVariance},
  centerVariance[x_List] := Variance@N[Norm[Mean@x - #] & /@ x];
  First@Nearest[vlist -> cols, centerVariance@zone]]

colorRules[zones_List] := (# -> colorAssign[#] & /@ zones)

main[urlName_String] := 
 Module[{pixels, FgPixelPositions, rawZones, zones},
  pixels = ImageData@Import@urlName;
  FgPixelPositions = Position[pixels, 1];
  (*fill and separate the regions*)
  rawZones = NestList[findOneZone[#] &, {FgPixelPositions, {}}, 4];
  zones = Rest[rawZones][[All, 2]];
  (*Identify,colorize and render*)
  Image@ReplacePart[ConstantArray[{0, 0, 0}, Dimensions@pixels], 
    colorRules[zones]]]

s = {"http://i.stack.imgur.com/Oa2O1.png"};
main /@ s

2

Пітон, 579 577 554 514 502 501 байт

Для кожної форми залийте її заливкою, потім обчисліть відстань між центроїдом та найдальшою точкою.

тоді реальна поверхня форми порівнюється з поверхнею трикутника, квадрата, диска або колеса, які мали б однаковий розмір.

імпортна математика ; від PIL . Імпорт зображення *; A , R , _ , I = abs , діапазон ( 300 ), 255 , відкритий ( sys . Argv [ 1 ]). конвертувати ( 'P' ); Q = я . load () для j в R : для i в R : якщо Q [ 

 
  i , j ] == _ : 
   X , Y , s , z , p = 0 , 0 , 0 , [], [( i , j )], тоді як p : 
    a , b = n = p . pop (), якщо ні ( Q [ n ]! = _ або n в z ): 
     X + = a ; Y + =
   
     б ; z + = [ n ]; p + = [( a , b - 1 ), ( a + 1 , b ), ( a , b + 1 ), ( a - 1 , b )]; s + = 1 
   г = макс ([ математики . hypot ( Х / с - х , У / з - у ) для х , у в з ]); C = { 1 : A ( s - ( 1,4 * r ) ** 2 ), 2 : A ( s - r * r / 3 ), 3 : A ( s - математика . Pi * r * r ), 4 : A ( s - 2,5 * r * r )} для p в z
   : 
    Q [ р ] = хв ( С , ключ = С . Отримуємо ) 
I . putpalette ([ 0 , 0 , 0 , _ ] * 3 + [ _ , _ , 0 ]) 
Я . показати ()

1

C # 1086 байт

Ще одне рішення щодо заливки, просто для запису, оскільки тут немає версії C #. Як і Quincunx, я хотів довести себе, що я можу це зробити, і не дуже сильно відрізняється його підхід у Java.

  • Це рішення не використовує ніяких рекурсій (а стек), тому що я продовжував працювати в StackOverflows.
  • Виявлення межових пікселів спрощується за допомогою перегляду 4 наступних пікселів, якщо будь-який із них чорного кольору, ток - граничний піксель.

Він приймає кожен формат зображення.

  • Параметр 1 = InputPath
  • Параметр 2 = OutputPath

Ймовірно, можна зняти кілька символів, видаливши всі статичні речі та створивши екземпляр програми.

Читаема версія:

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;

class Program
{
    static Bitmap img;
    static int w, h;
    static ISet<Point> pointsDone = new HashSet<Point>();
    static void Main(string[] a)
    {
        img = new Bitmap(a[0]);
        w = img.Width;
        h = img.Height;
        Bitmap clone = new Bitmap(w,h, PixelFormat.Format32bppArgb);
        Graphics.FromImage(clone).DrawImage(img, 0, 0, w, h);
        img = clone;




        Color[] colors = new[] { Color.Blue, Color.Red, Color.Green, Color.Yellow };

        var shapes = new List<ISet<Tuple<bool, Point>>>();
        for(int x=0;x<w;x++)
            for (int y = 0; y < h; y++)
            {
                Point p = new Point(x, y);
                if (pointsDone.Add(p) && _isWhitePixel(p))
                    shapes.Add(_detectShape(p));
            }
        int index = 0;
        foreach (var shp in shapes.OrderBy(shp => shp.Count(item => item.Item1)))
        {
            foreach (var pixel in shp)
                img.SetPixel(pixel.Item2.X, pixel.Item2.Y, colors[index]);
            index++;
        }

        img.Save(a[1]);
    }

    private static ISet<Tuple<bool, Point>> _detectShape(Point p)
    {
        var todo = new Stack<Point>(new[] { p });
        var shape = new HashSet<Tuple<bool, Point>>();
        do
        {
            p = todo.Pop();
            var isBorderPixel = false;
            foreach (var n in new[] { new Point(p.X + 1, p.Y), new Point(p.X - 1, p.Y), new Point(p.X, p.Y + 1), new Point(p.X, p.Y - 1) })
                if (_isWhitePixel(n))
                {
                    if (pointsDone.Add(n))
                        todo.Push(n);
                }
                else isBorderPixel = true; // We know we are at the border of the shape
            shape.Add(Tuple.Create(isBorderPixel, p));

        } while (todo.Count > 0);
        return shape;
    }

    static bool _isWhitePixel(Point p)
    {
        return img.GetPixel(p.X, p.Y).ToArgb() == Color.White.ToArgb();
    }
}

Гольф:

using System;using System.Collections.Generic;using System.Drawing;using System.Drawing.Imaging;using System.Linq;class P{static Bitmap a;static int w,h;static ISet<Point> d=new HashSet<Point>();static void Main(string[] q){a=new Bitmap(q[0]);w=a.Width;h=a.Height;var c=new Bitmap(w,h,PixelFormat.Format32bppArgb);Graphics.FromImage(c).DrawImage(a,0,0,w,h);a=c;var e=new[]{Color.Blue,Color.Red,Color.Green,Color.Yellow};var f=new List<ISet<dynamic>>();for(int x=0;x<w;x++)for(int y=0;y<h;y++){Point p=new Point(x,y);if (d.Add(p)&&v(p))f.Add(u(p));}int i=0;foreach(var s in f.OrderBy(s=>s.Count(item=>item.b))){foreach(var x in s)a.SetPixel(x.p.X,x.p.Y,e[i]);i++;}a.Save(q[1]);}private static ISet<dynamic> u(Point p){var t=new Stack<Point>(new[]{p});var s=new HashSet<dynamic>();do{p=t.Pop();var b=false;foreach(var n in new[]{new Point(p.X+1,p.Y),new Point(p.X-1,p.Y),new Point(p.X,p.Y+1),new Point(p.X,p.Y-1)})if(v(n)){if (d.Add(n))t.Push(n);}else b=true;s.Add(new{b,p});}while (t.Count>0);return s;}static bool v(Point p){return a.GetPixel(p.X,p.Y).ToArgb()==Color.White.ToArgb();}}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.