Прослеживание оттенков изображения


17

Загрузите изображение в этот фрагмент стека и наведите на него указатель мыши. Будет нарисована черная кривая, которая следует за углом оттенка , начиная с точки курсора:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script><style>canvas{border:1px solid black;}</style>Load an image: <input type='file' onchange='load(this)'><br><br>Max length <input id='length' type='text' value='300'><br><br><div id='coords'></div><br><canvas id='c' width='100' height='100'>Your browser doesn't support the HTML5 canvas tag.</canvas><script>function load(t){if(t.files&&t.files[0]){var e=new FileReader;e.onload=setupImage,e.readAsDataURL(t.files[0])}}function setupImage(t){function e(t){t.attr("width",img.width),t.attr("height",img.height);var e=t[0].getContext("2d");return e.drawImage(img,0,0),e}img=$("<img>").attr("src",t.target.result)[0],ctx=e($("#c")),ctxRead=e($("<canvas>"))}function findPos(t){var e=0,a=0;if(t.offsetParent){do e+=t.offsetLeft,a+=t.offsetTop;while(t=t.offsetParent);return{x:e,y:a}}return void 0}$("#c").mousemove(function(t){function e(t,e){var a=ctxRead.getImageData(t,e,1,1).data,i=a[0]/255,r=a[1]/255,o=a[2]/255;return Math.atan2(Math.sqrt(3)*(r-o),2*i-r-o)}if("undefined"!=typeof img){var a=findPos(this),i=t.pageX-a.x,r=t.pageY-a.y;$("#coords").html("x = "+i.toString()+", y = "+r.toString());var o=parseInt($("#length").val());if(isNaN(o))return void alert("Bad max length!");for(var n=[i],f=[r],h=0;n[h]>=0&&n[h]<this.width&&f[h]>=0&&f[h]<this.height&&o>h;)n.push(n[h]+Math.cos(e(n[h],f[h]))),f.push(f[h]-Math.sin(e(n[h],f[h]))),h++;ctx.clearRect(0,0,this.width,this.height),ctx.drawImage(img,0,0);for(var h=0;h<n.length;h++)ctx.fillRect(Math.floor(n[h]),Math.floor(f[h]),1,1)}});</script>

Я тестировал этот фрагмент только в Google Chrome.

Например, когда курсор находится над красным, кривая имеет наклон 0 °, но когда она выше желтого, она имеет наклон 60 °. Кривая продолжается для указанной длины, непрерывно изменяя свой наклон в соответствии с оттенком.

Загрузите это изображение, и когда вы наводите курсор на него, линия вокруг курсора должна сделать полный оборот против часовой стрелки:

углы оттенка

Это и это другие аккуратные образы, чтобы попробовать. (Вам необходимо сохранить их, а затем загрузить их с фрагментом кода. Они не могут быть связаны напрямую из-за ограничений перекрестного происхождения.)

Вот не уменьшенная версия фрагмента:

Вызов

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

В частности, начните кривую с (x, y) и измерьте угол оттенка там. Перейдите на одну единицу (ширину одного пикселя) в этом направлении, отметив, что ваша новая позиция, скорее всего, не является целочисленной координатой . Отметьте другую точку на кривой и двигайтесь снова, используя оттенок от ближайшего пикселя (используя что-то вроде floorили round, я не буду проверять это точно). Продолжайте так до тех пор, пока кривая не выйдет за пределы или не превысит максимальную длину. Чтобы закончить, нанесите все точки кривой как отдельные черные пиксели (опять же, используйте ближайшие пиксели), наложенные на изображение, и выведите это новое изображение.

«Угол оттенка» - это просто оттенок :

hue = atan2(sqrt(3) * (G - B), 2 * R - G - B)

Обратите внимание, что для значений оттенков серого, которые технически не имеют оттенка, возвращается 0, но это нормально.

(Эта формула использует atan2большинство встроенных математических библиотек. R, G, B - от 0 до 1, а не от 0 до 255.)

  • Вы можете использовать любой распространенный формат изображения без потерь, а также любые библиотеки изображений.
  • Возьмите ввод из stdin или из командной строки или напишите функцию с аргументами для имени файла изображения, x и y и максимальной длины.
  • Максимальная длина, а x и y всегда являются неотрицательными целыми числами. Вы можете предположить, что x и y находятся в диапазоне.
  • Сохраните выходное изображение с выбранным вами именем или просто отобразите его.
  • Ваша реализация не обязательно должна соответствовать фрагменту. Несколько пикселей в немного разных местах из-за немного другого метода округления / вычисления - это хорошо. (В хаотических случаях это может привести к появлению кривых, которые в основном отличаются друг от друга, но пока они выглядят правильно, это нормально.)

счет

Наименьшая подача в байтах побеждает.


1
Фрагмент полностью сломан в Firefox.
Ypnypn

Фрагмент также не работает в Safari. (Крутой вызов, хотя, +1)
Алекс А.

@ Хобби Кальвина Можем ли мы поболтать? chat.stackexchange.com/rooms/22029/…
BrainSteel

Ответы:


2

МАТЛАБ, 136

function t(g,x,y,l)
m=imread(g);imshow(m); h=2*pi*rgb2hsv(m);h=h(:,:,1);s=streamline(cos(h),-sin(h),x,y,[1,l]);set(s,'LineW',1,'Co','k');

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


5

C с SDL, 549 516 байт

Я начну эту вечеринку! Почему-то мне захотелось попробовать свои силы в гольфе сегодня вечером. То, что вы, ребята, делаете сложно ... Если есть что-то, чего я не вижу на этом сайте, это SDL. Возможно, я только что узнал почему. Этот конкретный фрагмент соответствует как SDL2, так и SDL1.2, но является жестоким. Называется как f("imagename.bmp", xcoord, ycoord, max_length);. Сохраняет файл с тем же именем, которое указано в аргументах. Вывод, похоже, очень похож на фрагмент кода OP, но «нечеткий». Я могу попытаться исправить это чуть позже.

#include"SDL.h"
f(char*C,x,y,m){SDL_Surface*P=SDL_LoadBMP(C);int p=P->pitch,i=P->format->BytesPerPixel,q=0;double X=x,Y=y,f=255,R,G,B,h;Uint8*Q,d=1,r,g,b,k;while(d){Q=P->pixels+y*p+i*x;SDL_GetRGB(i==4?*(Uint32*)Q:i==3?SDL_BYTEORDER==4321?*Q<<16|Q[1]<<8|Q[2]:*Q|Q[1]<<8|Q[2]<<16:i==2?*(Uint16*)Q:*Q,P->format,&r,&g,&b);R=r/f;G=g/f;B=b/f;h=atan2(sqrt(3)*(G-B),2*R-G-B);for(k=0;k<i;k++)Q[k]=0;X+=cos(h);Y-=sin(h);if((int)X-x|(int)Y-y)q++;x=X;y=Y;d=x<0|x>=P->w|y<0|y>=P->h|q>=m?0:1;}SDL_SaveBMP(P,C);SDL_FreeSurface(P);}

Здесь все распутано:

#include"SDL.h"
f(char*C,x,y,m){
    SDL_Surface*P=SDL_LoadBMP(C);
    int p=P->pitch,i=P->format->BytesPerPixel,q=0;
    double X=x,Y=y,f=255,R,G,B,h;
    Uint8*Q,d=1,r,g,b,k;
    while(d){
        Q=P->pixels+y*p+i*x;
        SDL_GetRGB(i==4?*(Uint32*)Q:i==3?SDL_BYTEORDER==4321?*Q<<16|Q[1]<<8|Q[2]:*Q|Q[1]<<8|Q[2]<<16:i==2?*(Uint16*)Q:*Q,P->format,&r,&g,&b);
        R=r/f;
        G=g/f;
        B=b/f;
        h=atan2(sqrt(3)*(G-B),2*R-G-B);
        for(k=0;k<i;k++)Q[k]=0;
        X+=cos(h);
        Y-=sin(h);
        if((int)X-x|(int)Y-y)q++;
        x=X;y=Y;
        d=x<0|x>=P->w|y<0|y>=P->h|q>=m?0:1;
    }
    SDL_SaveBMP(P,C);
    SDL_FreeSurface(P);
}

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

РЕДАКТИРОВАТЬ-------

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

f("HueTest1.bmp", 270, 40, 200);

HueTest1.bmp

f("HueTest2.bmp", 50, 50, 200);

HueTest2.bmp

f("HueTest3.bmp", 400, 400, 300);

HueTest3.bmp


3

Python, 203 172

from scipy.misc import*
def f(i,x,y,l):
 a=imread(i);Y,X,_=a.shape;o=a.copy()
 while(X>x>0<y<Y<[]>l>0):r,g,b=a[y,x]/255.;o[y,x]=0;l-=1;x+=2*r-g-b;y-=3**.5*(g-b);imsave(i,o)

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

Позвонить с f("image.jpg", 400, 400, 300)

Я потратил много символов на импорт, если у кого-то есть предложения по его улучшению. Может не работать в 3.0


С быстрым взглядом: sqrt(3) -> 3**.5? Я ничего не могу придумать для импорта, хотя.
Sp3000

Хороший! Это будет полезно в будущем.
grovesNL

3

МАТЛАБ, 186 172

Игра включена ! Вызовите как t('YourImage.ext',123,456,100')для изображения любого типа, поддерживаемого MATLAB, начиная с (x, y) = (123 456) и максимальной длины 100. Начальные позиции не могут быть точно на правом и нижнем краях (это будет стоить мне два байта), поэтому начать на краю, использовать что-то вроде, x=799.99чтобы начать в x=800. Индексирование начинается с 1, а не с 0.

Код:

function t(g,x,y,l)
m=imread(g);[Y,X,~]=size(m);h=2*pi*rgb2hsv(m);while(x>0&x<X&y>0&y<Y&l)
p=ceil(x);q=ceil(y);m(q,p,:)=0;a=h(q,p);x=x+cos(a);y=y-sin(a);l=l-1;end
imshow(m)

Изменения:

  • Изменено с линии с предыдущего на следующий пиксель на простую точку в пикселе, так как линия никогда не будет длиннее пикселя! Все еще использую, lineтак как это самый короткий код, который я знаю для создания пикселя.
  • Изменил цвет с черного на синий, используя Coрасширение до Color(что делает MATLAB автоматически)
  • Изменен порядок вычисления следующей позиции и рисования точки, так как благодаря @grovesNL я понял, что фактически вытягиваю границы, так как я проверял границы после изменения позиции.
  • Изменено с рисования линий на установку матрицы rgb на 0 и отображение после.

Черная линия конфеты


Нет x=0или y=0потенциально действительные позиции?
grovesNL

Кроме того, как это 166 байтов?
grovesNL

@grovesNL Извините, случайно посчитал мою тестовую версию без functionзаголовка. Спецификация не требует индексации с нуля или на основе одного, так что я использую MATLAB на основе одного, поэтому нет, x=0или y=0она недопустима в этой программе.
Sanchises

Ах, я забыл, что MATLAB был односторонним (это было давно). Но я думаю, что может сделать x=Xи y=Yдействует вместо этого?
grovesNL

1
Хах! Победи себя в своей игре, мое решение MATLAB всего 135 символов!
AJMansfield

1

Обработка 323 символа

void h(String f,float x,float y,float m){PImage i=loadImage(f);PImage i2=loadImage(f);while(m>0){color c=i.get((int)x,(int)y);float r=red(c)/255;float g=green(c)/255;float b=blue(c)/255;float h=atan2(sqrt(3)*(g-b),2*r-g-b);float dx=cos(h);float dy=-sin(h);m-=1;x+=dx;y+=dy;i2.set((int)x,(int)y,color(0));}i2.save("o.png");}

С пробелами:

void h(String f, float x, float y, float m) {
  PImage i = loadImage(f);
  PImage i2 = loadImage(f);

  while (m > 0) {

    color c = i.get((int)x, (int)y);
    float r = red(c)/255;
    float g = green(c)/255;
    float b = blue(c)/255;
    float h = atan2(sqrt(3) * (g - b), 2 * r - g - b);

    float dx = cos(h);
    float dy = -sin(h);

    m-= 1;
    x += dx;
    y += dy;

    i2.set((int)x, (int)y, color(0));
  }

  i2.save("o.png");
}

оттенок прослеженного изображения

Я уверен, что мог бы сократить это дальше, но пока это работает.


0

JavaScript 414

function P(G,x,y,l){
I=new Image()
I.onload=function(){d=document,M=Math,C=d.createElement('canvas')
d.body.appendChild(C)
w=C.width=I.width,h=C.height=I.height,X=C.getContext('2d')
X.drawImage(I,0,0)
D=X.getImageData(0,0,w,h),d=D.data,m=255,i=0
for(;l--;i=(w*~~y+~~x)*4,r=d[i]/m,g=d[i+1]/m,b=d[i+2]/m,H=M.atan2(M.sqrt(3)*(g-b),2*r-g-b),d[i]=d[i+1]=d[i+2]=0,x+=M.cos(H),y-=M.sin(H))
X.putImageData(D,0,0)}
I.src=G}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.