追踪图像的色调


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)
Alex A.

@Calvin的爱好我们可以聊天吗?chat.stackexchange.com/rooms/22029/…–
BrainSteel

Answers:


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

带有SDL的C,549字节

我将开始这个聚会!由于某种原因,我觉得今晚想去打高尔夫球。你们很难做...如果有一件事情我在本网站上没有看到,那就是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,2015年

3

MATLAB,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=0y=0可能有效的职位?
grovesNL,2015年

另外,这166个字节如何?
grovesNL,2015年

@grovesNL对不起,我不小心计算了没有function标题的测试版本。Spec不需要从零开始或从一开始的索引,因此我使用的是MATLAB的从一开始的索引,所以没有,x=0或者y=0在该程序中无效。
桑奇斯

啊,我忘了MATLAB是基于基础的(已经有一段时间了)。但我想,可能使x=Xy=Y有效的呢?
grovesNL,2015年

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}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.