Відстеження відтінків зображення


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 - це завжди негативні цілі числа. Можна припустити, що х і у знаходяться в діапазоні.
  • Збережіть вихідне зображення з вибором імені або просто покажіть його.
  • Ваша реалізація не повинна точно відповідати фрагменту. Кілька пікселів у дещо різних місцях через дещо інший метод округлення / обчислення - це добре. (У хаотичних випадках це може призвести до кривих, які в кінцевому підсумку відрізняються, але поки вони візуально виглядають правильно, це добре.)

Оцінка балів

Виграє найменше подання в байтах .


1
Фрагмент повністю розбитий у Firefox.
Ypnypn

Знімок також не працює в Safari. (Хороший виклик, хоча, +1)
Алекс А.

@ Хобі Кальвіна Чи можемо ми спілкуватися? chat.stackexchange.com/rooms/22029/…
BrainSteel

Відповіді:


2

MATLAB, 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

Пітон, 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 байт?
гаїNL

@grovesNL Вибачте, випадково порахував мою тестову версію без functionзаголовка. Spec не вимагав нульової або одноосновної індексації, тому я використовую однонаціональний MATLAB, тому ні, x=0або y=0недійсний у цій програмі.
Санчіз

Ах, я забув, що MATLAB був заснований на одній основі (минуло певний час). Але я думаю, що це може зробити x=Xі y=Yдійсним замість цього?
гаїNL

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.