Черно-белые радуги

60

Учитывая изображение, которое имеет только черные и белые пиксели и местоположение (x, y), которое является белым пикселем, раскрасьте белые пиксели на основе их минимального Манхэттенского расстояния от (x, y) в пути, который включает в себя только прохождение других белых пикселей.

Оттенок из цветных пикселей должен быть пропорционален расстоянию от (х, у), так что пиксель в точке (х, у) будет иметь цветовой тон от 0 ° (чистого красного цвета) и пиксели , наиболее удаленных от (х, у) будет иметь оттенок 360 ° (также красный), а другие оттенки будут плавно и линейно смешиваться между ними. Насыщенность и значение оба должны быть 100%.

Если белый пиксель не подключен к (x, y) через другие белые пиксели, он должен оставаться белым.

подробности

  • Входные данные будут состоять из имени файла изображения или необработанных данных изображения, а также целых чисел x и y.
  • Выходное изображение может быть сохранено в файл или передано в необработанном виде в стандартный формат файла изображения или просто отображено.
  • Значение x равно 0 в крайнем левом пикселе и увеличивается при движении вправо. Значение y равно 0 в верхних пикселях и увеличивается при спуске. (x, y) всегда будет в границах изображения.
  • Разрешены как полные программы, так и функции.

Самый короткий код в байтах побеждает.

Примеры

Все эти изображения были уменьшены для экономии места. Нажмите на них, чтобы просмотреть в полном размере.

Входное изображение:

пример 1 ввода

(x,y) = (165,155) а также (x,y) = (0,0)

пример 1, вывод А пример 1, выход B


Введите изображение и выведите с помощью (x,y) = (0,0):

Пример 5 ввода Пример 5 ввода А


Введите изображение и выведите с помощью (x,y) = (600,350):

пример 2 ввода пример 2 вывод


Введите изображение и выведите с помощью (x,y) = (0,0):

Пример 3 ввода пример 3 вывод


Введите изображение и выведите с помощью (x,y) = (0,0):

пример 4 ввода пример 4 вывода


Дополнительный бонус -30%: используйте евклидово расстояние. Предложение для вашего алгоритма следующее (общий план):

  1. Есть стартовый пиксель.
  2. Заполните поток от этого пикселя.
  3. Для каждого пикселя, достигнутого в заливке,
  4. Переходите от начального пикселя к этому пикселю с шагом в половину единицы по прямой линии.
  5. На каждом шаге применяйте int()координаты x и y. Если пиксель в этих координатах черный, остановитесь. В противном случае продолжайте. (Это метод прямой видимости.)
  6. Любой достигнутый пиксель, который граничит с белым пикселем и / или пикселем, который ранее был помечен на значительно большем расстоянии (т.е. +10), становится стартовым пикселем.

В более мета-смысле, этот алгоритм распространяется на каждый пиксель, доступный по прямой линии от начальных / уже окрашенных пикселей, а затем «дюймов» вокруг краев. Бит «значительно большее расстояние» предназначен для ускорения алгоритма. Честно говоря, неважно, как вы реализуете евклидово расстояние, просто это должно выглядеть примерно так.

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

Введите изображение и (x,y) = (165,155)

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


Большое спасибо Calvin'sHobbies и trichoplax за помощь в написании этой задачи! Веселиться!

El'ndia Starman
источник
7
Я не планирую играть в гольф, но я сделал версию Javascript, где вы можете навести курсор мыши на изображение, и цвета мгновенно обновятся. Тестовые изображения здесь слишком велики для быстрого запуска, поэтому я бы посоветовал попробовать меньшие изображения, такие как эта или эта .
Увлечения Кэлвина
Это круто! Я подозреваю, что это слишком эффективно, чтобы быть хорошей базой для игры в гольф =)
flawr
2
Лабиринты намного легче решить, когда они окрашены в такой цвет!
mbomb007
Последний пример действительно красивый. Является ли входное изображение просто шумом?
Дилнан
@dylnan: Если вы говорите о примере прямо перед бонусом, это на самом деле лабиринт. Вы можете нажать на него, чтобы увидеть его в полном размере.
El'endia Starman

Ответы:

33

Matlab, 255 245 231 байт

Это ожидает имя изображения сначала, потом yи потом x.

I=@input;i=imread(I('','s'));[r,c]=size(i);m=zeros(r,c);m(I(''),I(''))=1;M=m;d=m;K=[1,2,1];for k=1:r*c;d(m&~M)=k;M=m;m=~~conv2(m,K'*K>1,'s');m(~i)=0;end;z=max(d(:));v=[1,1,3];imshow(ind2rgb(d,hsv(z)).*repmat(m,v)+repmat(~d&i,v),[])

Я реализовал заливку (или, если хотите, «dijkstra для 4-окрестностей»), сначала создав маску, в которой начальный пиксель установлен в 1, с накопителем расстояния (оба размера изображения), а затем повторив следующее шаги:

  • сверните маску с ядром с четырьмя соседями (это очень неэффективная часть)
  • установите все ненулевые пиксели маски на 1
  • установить все черные пиксели изображения на ноль
  • установите все значения в аккумуляторе, где маска изменилась на этом шаге, чтобы k
  • увеличение k
  • повторять до тех пор, пока в маске больше не будет изменений (на самом деле я не проверяю это условие, а просто использую количество пикселей на изображении в качестве верхней границы, которая обычно является очень плохой верхней границей, но это codegolf =)

Это оставляет нам манхэттенские расстояния каждого пикселя до начального пикселя в аккумуляторе расстояний. Затем мы создаем новое изображение, проходя через заданный диапазон цветов и сопоставляя «первый» оттенок с нулевым значением, а «последний» - с максимальным расстоянием.

Примеры

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

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

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

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

В качестве бонуса, здесь красивая картинка того, как рассчитывается расстояние. ярче = дальше.

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

flawr
источник
3
Это то, что я хотел бы распечатать для моей дочери.
rayryeng - Восстановить Монику
@rayryeng Шаблоны - работа Элэндии Старман, а не моя =)
flawr
Вы по-прежнему ставите цвета на изображения: D. Вы сделали последний шаг.
rayryeng - Восстановить Монику
4
Я впечатлен. Я едва мог понять вызов LOL
Zfrisch
Честно говоря, я хочу использовать его для создания пейзажей.
CorsiKa
3

Blitz 2D / 3D , 3068 * 0,7 = 2147,6

Это эталонная реализация для евклидова алгоритма гольфа.

image=LoadImage("HueEverywhere_example1.png")
Graphics ImageWidth(image),ImageHeight(image)
image=LoadImage("HueEverywhere_example1.png")
x=0
y=0
w=ImageWidth(image)
h=ImageHeight(image)
Type start
Field x,y
Field dis#
Field nex.start
End Type
Type cell
Field x,y
Field dis#
End Type
Type oldCell
Field x,y
Field dis#
End Type
initCell.start=New start
initCell\x=x
initCell\y=y
initCell\dis=1
Dim array#(w,h)
imgBuff=ImageBuffer(image)
LockBuffer(imgBuff)
s.start=First start
colr=col(0,0,0)
colg=col(0,0,1)
colb=col(0,0,2)
newcol=colr*256*256+colg*256+colb
WritePixelFast(s\x,s\y,newcol,imgBuff)
While s<>Null
c.cell=New cell
c\x=s\x
c\y=s\y
c\dis=s\dis
While c<>Null
For dy=-1To 1
For dx=-1To 1
If dx*dy=0And dx+dy<>0
nx=c\x+dx
ny=c\y+dy
ndis#=s\dis+Sqr#((nx-s\x)*(nx-s\x)+(ny-s\y)*(ny-s\y))
If nx >= 0And nx<w And ny >= 0And ny<h
If KeyHit(1)End
pixcol=ReadPixelFast(nx,ny,imgBuff)
If pixcol<>-16777216
If array(nx,ny)=0Or ndis<array(nx,ny)
check=1
steps=Ceil(dis)*2
For k=0 To steps
r#=k*1./steps
offx#=Int(s\x+(c\x-s\x)*r)
offy#=Int(s\y+(c\y-s\y)*r)
pixcol2=ReadPixelFast(offx,offy,imgBuff)
If pixcol2=-16777216
check=0
Exit
EndIf
Next
If check
array(nx,ny)=ndis
newCell.cell=New cell
newCell\x=nx
newCell\y=ny
newCell\dis=ndis
EndIf
EndIf
EndIf
EndIf
EndIf
Next
Next
o.oldCell=New oldCell
o\x=c\x
o\y=c\y
o\dis=c\dis
Delete c
c=First cell
Wend
For o.oldCell=Each oldCell
bordersWhite=0
For dy=-1To 1
For dx=-1To 1
If dx<>0Or dy<>0
nx=o\x+dx
ny=o\y+dy
If nx>=0And nx<w And ny>=0And ny<h
pixcol=ReadPixelFast(nx,ny,imgBuff)
If (pixcol=-1And array(nx,ny)=0)Or array(nx,ny)>o\dis+9
bordersWhite=1
Exit
EndIf
EndIf
EndIf
Next
If bordersWhite Exit
Next
If bordersWhite
ns.start=New start
ns\x=o\x
ns\y=o\y
ns\dis=o\dis
s2.start=First start
While s2\nex<>Null
If ns\dis<s2\nex\dis
Exit
EndIf
s2=s2\nex
Wend
ns\nex=s2\nex
s2\nex=ns
EndIf
Delete o
Next
EndIf
s2=s
s=s\nex
Delete s2
Wend
maxDis=0
For j=0To h
For i=0To w
If array(i,j)>maxDis maxDis=array(i,j)
Next
Next
For j=0To h
For i=0To w
dis2#=array(i,j)*360./maxDis
If array(i,j) <> 0
colr=col(dis2,0,0)
colg=col(dis2,0,1)
colb=col(dis2,0,2)
newcol=colr*256*256+colg*256+colb
WritePixelFast(i,j,newcol,imgBuff)
EndIf
Next
Next
UnlockBuffer(imgBuff)
DrawImage image,0,0
Function col(ang1#,ang2#,kind)
While ang1>360
ang1=ang1-360
Wend
While ang1<0 
ang1=ang1+360
Wend
While ang2>180
ang2=ang2-360
Wend
While ang2<-180
ang2=ang2+360
Wend
a3#=ang2/180.
If ang1>300
diff#=(ang1-300)/60.
r=255
g=0
b=255*(1-diff)
ElseIf ang1>240
diff#=(ang1-240)/60.
r=255*diff
g=0
b=255
ElseIf ang1>180
diff#=(ang1-180)/60.
r=0
g=255*(1-diff)
b=255
ElseIf ang1>120
diff#=(ang1-120)/60.
r=0
g=255
b=255*diff
ElseIf ang1>60
diff#=(ang1-60)/60.
r=255*(1-diff)
g=255
b=0
Else
diff#=(ang1-00)/60.
r=255
g=255*diff
b=0
EndIf
If a3>0
r2=r+a3*(255-r)
g2=g+a3*(255-g)
b2=b+a3*(255-b)
Else
r2=r+a3*r
g2=g+a3*g
b2=b+a3*b
EndIf
If r2>255
r2=255
ElseIf r2<0
r2=0
EndIf
If g2>255
g2=255
ElseIf g2<0
g2=0
EndIf
If b2>255
b2=255
ElseIf b2<0
b2=0
EndIf
If kind=0
Return r2
ElseIf kind=1
Return g2
ElseIf kind=2
Return b2
Else
Return 0
EndIf
End Function

На самом деле, я ненавижу, как это нечитаемо по сравнению с оригиналом. (Между прочим, это 5305 байт.) На самом деле, я мог бы выделить еще несколько байтов, используя однозначные имена переменных для всего, но это уже довольно смешно. И это не победит в ближайшее время. :П

El'ndia Starman
источник
2

C ++ / SFML: 1271 1235 1226 байт

-36 байт благодаря пользователю 202729 -9 байт благодаря Zacharý

#include<SFML\Graphics.hpp>
#include<iostream>
#define V std::vector
#define P e.push_back
#define G(d,a,b,c) case d:return C(a,b,c);
#define FI(r,s)(std::find_if(e.begin(),e.end(),[&a](const T&b){return b==T{a.x+(r),a.y+(s),0};})!=e.end())
using namespace sf;using C=Color;struct T{int x,y,c;bool operator==(const T&a)const{return x==a.x&&y==a.y;}};int max(V<V<int>>&v){int m=INT_MIN;for(auto&a:v)for(auto&b:a)m=b>m?b:m;return m;}C hsv2rgb(int t){int ti=t/60%6;float f=t/60.f-ti,m=(1.f-f)*255,n=f*255;switch(ti){G(0,255,n,0)G(1,m,255,0)G(2,0,255,n)G(3,0,m,255)G(4,n,0,255)G(5,255,0,m)default:throw std::exception();}}void r(Image&a,int x,int y){auto d=a.getSize();V<V<int>>m(d.x,V<int>(d.y));int i=0,j,c=0,t;for(;i<d.y;++i)for(j=0;j<d.x;++j)m[j][i]=a.getPixel(j,i)==C::Black?-1:0;V<T>e{{x,y,1}};while(e.size()){V<T>t=std::move(e);for(auto&a:t){m[a.x][a.y]=a.c;if(a.x>0&&m[a.x-1][a.y]==0&&!FI(-1,0))P({a.x-1,a.y,a.c+1});if(a.y>0&&m[a.x][a.y-1]==0&&!FI(0,-1))P({a.x,a.y-1,a.c+1});if(a.x<m.size()-1&&m[a.x+1][a.y]==0&&!FI(1,0))P({a.x+1,a.y,a.c+1});if(a.y<m[0].size()-1&&m[a.x][a.y+1]==0&&!FI(0,1))P({a.x,a.y+1,a.c+1});}}c=max(m)-1;for(i=0,j;i<d.y;++i)for(j=0;j<d.x;++j)if(m[j][i]>0)a.setPixel(j,i,hsv2rgb(360.f*(m[j][i]-1)/c));}

sf::ImageПараметр также выходной сигнал (будет изменено). Вы можете использовать это так:

sf::Image img;
if (!img.loadFromFile(image_filename))
    return -1;

r(img, 0, 0);

if (!img.saveToFile(a_new_image_filename))
    return -2;

Первый параметр является входным изображение (и выход), вторые и третьи параметрами являются xи yпараметром , где он должен начать

HatsuPointerKun
источник
Случай с переключателем кажется настолько расточительным, что, вероятно, было бы полезно определение макроса ... Кроме того, `` at setPixel(j, i,hsv2и FI(xm,ym) (std::find_ifдействительно ли это необходимо?
user202729
Вы можете удалить пространство между G(d,a,b,c)и case d:. Кроме того, пространство между case d:и return C(a,b,c)не требуется, а также. (b>m?b:m)не требует скобок, а (t/60)%6=> t/60%6по порядку операций.
Захари
Возможно, вам также следует переименовать xmи ymсократить имена переменных
Zacharý
Я думаю , что это возможно , чтобы удалить пространство между G(d,a,b,c)и case, FI, ti, и hsv2rgbкаждый может быть заменен более коротким именем.
Захари
1

C ++, 979 969 898 859 848 байт

#include<cstdio>
#include<cstdlib>
#define K 400
#define L 400
#define M (i*)malloc(sizeof(i))
#define a(C,X,Y)if(C&&b[Y][X].c){t->n=M;t=t->n;b[Y][X].d=d+1;t->n=0;t->c=X;t->d=Y;}
#define A(n,d)case n:d;break;
#define F fgetc(f)
#define W(A,B) for(A=0;A<B;A++){
struct i{int c;int d;int v;i*n;}b[L][K]={0},*h,*t;float m=0;int main(){FILE*f=fopen("d","r+b");int x,y,d=0;W(y,L)W(x,K)b[y][x].c=F<<16|F<<8|F;}}rewind(f);x=165,y=155;h=M;h->c=x;h->d=y;b[y][x].d=d;t=h;while(h){i*p=b[h->d]+h->c;if(p->v)h=h->n;else{p->v=1;x=h->c;y=h->d;d=p->d;m=d>m?d:m;a(x>0,x-1,y)a(x<K-1,x+1,y)a(y>0,x,y-1)a(y<L-1,x,y+1)}}W(y,L)W(x,K)i p=b[y][x];unsigned char n=-1,h=p.d/(m/n),R=h%43*6,Q=n*(n-(n*R>>8))>>8,t=n*(n-(n*(n-R)>>8))>>8,r,g,b;switch(h/43){A(0,n,t,0)A(1,Q,n,0)A(2,0,n,t)A(3,0,Q,n)A(4,t,0,n)A(5,n,0,Q)}d=h?r|g<<8|b<<16:p.c?-1:0;fwrite(&d,1,3,f);}}}
  • Вход: файл данных RGB (содержится в файле: d)
  • Вывод: файл данных RGBA RGB (выводится в файл: d)
  • Пример: convert -depth 8 -size "400x400" test.png d.rgb && mv -f d.rgb d && g ++ -o test main.c && ./test
  • ПРИМЕЧАНИЕ: размер и запуск изображения контролируются на уровне источника, если это проблема, добавьте 50 байтов или что-то еще - мне просто было все равно, если честно.

Не совсем прямой "ungolf", но это был прототип C, который я сначала смоделировал:

#include "stdio.h"
#include "stdlib.h"

struct i{
    unsigned int c;
    int d;
    int v;
}b[400][400]={0};

typedef struct q{
    int x;
    int y;
    struct q *n;
}q;
q *qu;
q *t;
float m=0;
int get_dist(int x, int y)
{
    int d = 0;

}

void flood(int x,int y,int d){
    qu=malloc(sizeof(q));
    qu->x=x;qu->y=y;b[y][x].d=d;
    t=qu;
    while(qu){
        struct i *p = &b[qu->y][qu->x];
        if(p->v){qu=qu->n; continue;}
        p->v=1;x=qu->x;y=qu->y;d=p->d;
        #define a(C,X,Y) if(C&&b[Y][X].c){t->n=malloc(sizeof(q));t=t->n;b[Y][X].d=d+1;t->n=0;t->x=X;t->y=Y;}
        a(x>0,x-1,y);
        a(x<399,x+1,y);
        a(y>0,x,y-1);
        a(y<399,x,y+1);
        m=p->d>m?p->d:m;
    }
}

unsigned int C(int h)
{
    int r=0,g=0,b=0;
    int s=255,v=255;
    unsigned char R, qq, t;

    R = h%43*6; 

    qq = (v * (255 - ((s * R) >> 8))) >> 8;
    t = (v * (255 - ((s * (255 - R)) >> 8))) >> 8;

    switch (h / 43){
        case 0: r = v; g = t; break;
        case 1: r = qq; g = v; break;
        case 2: g = v; b = t; break;
        case 3: g = qq; b = v; break;
        case 4: r = t; b = v; break;
        case 5: r = v; b = qq; break;
    }

    return r|(g<<8)|(b<<16)|255<<24;
}

#define F fgetc(f)
int main()
{
    FILE *f=fopen("d", "r+b");
    for(int y=0; y<400; y++){
        for(int x=0; x<400; x++){
            b[y][x].c = (F<<24)|(F<<16)|(F<<8);
        }
    }
    rewind(f);
    flood(165,155,1);
    m/=255.f;
    for(int y=0; y<400; y++){
        for(int x=0; x<400; x++){
            struct i p = b[y][x];
            unsigned int h = C(p.d/m);
            int o = p.c?-1:255<<24;
            if(p.d)fwrite(&h,4,1,f);
            else fwrite(&o,4,1,f);
        }
    }
}

Многие концепции остаются схожими, но, несомненно, существует множество мелких изменений. Чтобы скомпилировать это как C, вам нужно использовать C11 (C99, вероятно, будет работать, но я только строго протестировал в C11).
Мне очень понравился этот вызов, спасибо, что дали мне идею попробовать что-то новое :).
Изменить: Гольф немного лучше.
Edit2: объединены две структуры, так что моя структура пикселей и очередь одинаковы, немного больше злоупотреблений макросами, и переформатировано использование 255, так что его можно определить как -1 при определении серии неподписанных символов, и, наконец, удалил вызов функции.
Edit3: повторно использовали еще несколько переменных, настройки приоритета оператора и преобразованный вывод в RGB, сохраняя альфа-канал.
Edit4: я думаю, что с этим я покончил, некоторые арифметические изменения указателя и небольшие изменения потока управления.

p4plus2
источник
0

Python 3 и matplotlib, 251 байт

from pylab import*
def f(i,p):
    h,w,_=i.shape;o=full((h,w),inf);q=[p+(0,)]
    while q:
        x,y,d=q.pop(0)
        if w>x>=0and h>y>=0and i[y,x,0]:o[y,x]=d;i[y,x]=0;d+=1;q+=[(x-1,y,d),(x+1,y,d),(x,y-1,d),(x,y+1,d)]
    imshow(i);imshow(o,'hsv')

В качестве входного значения используется массив nxy MxNx3, возвращаемый функцией matplotlib imshow(). Входные данные изменяются функцией, поэтому они должны быть скопированы заранее. Изображение отображается автоматически, если matplotlib находится в «интерактивном» режиме; в противном случае вызов show()должен быть добавлен еще на 7 байтов.

Вывод создается путем отображения исходного изображения, а затем отображения изображения радуги поверх него. Matplotlib удобно обрабатывать inf и nan как прозрачные, так что черно-белое изображение просвечивает.

Райан МакКэмпбелл
источник