为什么我的像素处理功能这么慢?

时间:2019-07-25 08:27:40

标签: performance drawing processing

好,所以我需要自己的像素操作功能。 在互联网上找到类似ths之类的东西,做了些改动,我的问题是,为什么这么懒? 我需要一个更大的项目,此功能似乎是个问题。我该怎么做才能改善它? 这是必要的代码:

  class kolo {
  int x;
  int y;
  kolo(int _x, int _y) {
    x=_x;
    y=_y;
  }
  void rysuj() {
    fill(255, 0, 0);
    circle(x, y, 60);
  }
}


ArrayList tab, punkty;
kolo p1=new kolo(100, 400);
kolo p2=new kolo(230, 400);
kolo p3=new kolo(360, 400);
kolo p4=new kolo(490, 400);
boolean drawing=true;
int N=20;


void setup() {
  size(800, 800);
  tab = new ArrayList<kolo>(4);
  punkty=new ArrayList<PVector>(N);
  tab.add(p1);
  tab.add(p2);
  tab.add(p3);
  tab.add(p4);

}

void draw() {
  background(0);

  p1.rysuj();
  p2.rysuj();
  p3.rysuj();
  p4.rysuj();
  stroke(100, 100, 100);
  line(p1.x, p1.y, p2.x, p2.y);
  line(p2.x, p2.y, p3.x, p3.y);
  line(p3.x, p3.y, p4.x, p4.y);
  for(int i=0; i<50; i++){
   putPixel(200, i+50, 255,255,255); 
  }

}


int teller() {
  if (dist(mouseX, mouseY, p1.x, p1.y) < 60) return 1;
  if (dist(mouseX, mouseY, p2.x, p2.y) < 60) return 2;
  if (dist(mouseX, mouseY, p3.x, p3.y) < 60) return 3;
  if (dist(mouseX, mouseY, p4.x, p4.y) < 60) return 4;
  else return 0;
}

void mouseDragged() {
  if (teller()==1) {
    p1.x=mouseX;
    p1.y=mouseY;
    redraw();
  }
  if (teller()==2) {
    p2.x=mouseX;
    p2.y=mouseY;
    redraw();
  }
  if (teller()==3) {
    p3.x=mouseX;
    p3.y=mouseY;
    redraw();
  }
  if (teller()==4) {
    p4.x=mouseX;
    p4.y=mouseY;
    redraw();
  }
}



void putPixel(int x, int y, int r, int g, int b) {
  loadPixels();
  drawing=true;
  for (int i = 0; i < width; i++) 
  {
    for (int j = 0; j < height; j++) 
    {

      int loc = x + y * width;
      if (loc<width*height)
        //print(loc);
        pixels[loc] = color(r, g, b);
      loc=0;
    }
  }
  updatePixels();
}

如果您自己尝试一下,您会发现用这些像素绘制的细线落后于整个草图,如果没有平滑的移动这些球。

1 个答案:

答案 0 :(得分:3)

在您的情况下,putPixel函数效率极低

它会循环遍历并更新草图中的所有所有像素,而每次调用时只需设置一个单个像素即可。它的作用与set()相同,只是缠绕时间更长且效率较低。

使用它的方式也效率低下:

  for(int i=0; i<50; i++){
   putPixel(200, i+50, 255,255,255); 
  }

这将绘制一条50像素高的线,与line(200,50,200,100);

完整列表:

class kolo {
  int x;
  int y;
  kolo(int _x, int _y) {
    x=_x;
    y=_y;
  }
  void rysuj() {
    fill(255, 0, 0);
    ellipse(x, y, 60,60);
  }
}


ArrayList tab, punkty;
kolo p1=new kolo(100, 400);
kolo p2=new kolo(230, 400);
kolo p3=new kolo(360, 400);
kolo p4=new kolo(490, 400);
boolean drawing=true;
int N=20;


void setup() {
  size(800, 800);
  tab = new ArrayList<kolo>(4);
  punkty=new ArrayList<PVector>(N);
  tab.add(p1);
  tab.add(p2);
  tab.add(p3);
  tab.add(p4);

}

void draw() {
  background(0);

  p1.rysuj();
  p2.rysuj();
  p3.rysuj();
  p4.rysuj();
  stroke(100, 100, 100);
  line(p1.x, p1.y, p2.x, p2.y);
  line(p2.x, p2.y, p3.x, p3.y);
  line(p3.x, p3.y, p4.x, p4.y);
  line(200,50,200,100);
  //for(int i=0; i<50; i++){
  // putPixel(200, i+50, 255,255,255); 
  //}
  surface.setTitle((int)frameRate + "fps");
}


int teller() {
  if (dist(mouseX, mouseY, p1.x, p1.y) < 60) return 1;
  if (dist(mouseX, mouseY, p2.x, p2.y) < 60) return 2;
  if (dist(mouseX, mouseY, p3.x, p3.y) < 60) return 3;
  if (dist(mouseX, mouseY, p4.x, p4.y) < 60) return 4;
  else return 0;
}

void mouseDragged() {
  if (teller()==1) {
    p1.x=mouseX;
    p1.y=mouseY;
    redraw();
  }
  if (teller()==2) {
    p2.x=mouseX;
    p2.y=mouseY;
    redraw();
  }
  if (teller()==3) {
    p3.x=mouseX;
    p3.y=mouseY;
    redraw();
  }
  if (teller()==4) {
    p4.x=mouseX;
    p4.y=mouseY;
    redraw();
  }
}



void putPixel(int x, int y, int r, int g, int b) {
  loadPixels();
  drawing=true;
  for (int i = 0; i < width; i++) 
  {
    for (int j = 0; j < height; j++) 
    {

      int loc = x + y * width;
      if (loc<width*height)
        //print(loc);
        pixels[loc] = color(r, g, b);
      loc=0;
    }
  }
  updatePixels();
}

当前,您的代码主要使用绘图功能(例如line()ellipse()等),而不是大量的像素操作。

如果您确实想操纵像素,则可以。 重要的是要知道set()设置了一个像素,但更新了整个图像。

处理像素的更有效方法是访问pixels\[\],分批处理许多像素,最后使用updatePixels()更新整个图像一次

您需要将pixels[]的x,y位置(2D数组索引)转换为单个1D索引。您的代码已经包含以下内容:x + y * width

set()示例:

import java.util.Arrays;

PImage canvas;

void setup(){
  size(300,300);
  canvas = createImage(width,height,RGB);
}

void draw(){
  manipulatePixels();
  // render pixels
  image(canvas,0,0);  
}

void manipulatePixels(){
  //clear frame
  Arrays.fill(canvas.pixels,0);
  //draw something
  float scalar = sin(frameCount * 0.1);
  slowCircle(canvas,mouseX,mouseY,(int)map(scalar,-1.0,1.0,10,30),color(map(scalar,-1.0,1.0,64,255)));
}

void slowCircle(PImage canvas,int x,int y,int radius,color fill){
  for(int py = y - radius; py < y + radius; py++){
    for(int px = x - radius; px < x + radius; px++){
      if(dist(x,y,px,py) < radius){
        canvas.set(px,py,fill);
      }
    }
  } 
}

pixels[]示例:

import java.util.Arrays;

PImage canvas;

void setup(){
  size(300,300);
  canvas = createImage(width,height,RGB);
}

void draw(){
  manipulatePixels();
  // render pixels
  image(canvas,0,0);  
}

void manipulatePixels(){
  //clear frame
  Arrays.fill(canvas.pixels,0);
  //draw something
  float scalar = sin(frameCount * 0.1);
  //slowEllipse(canvas,mouseX,mouseY,(int)map(scalar,-1.0,1.0,10,30),color(map(scalar,-1.0,1.0,64,255)));
  fastCircle(canvas,mouseX,mouseY,(int)map(scalar,-1.0,1.0,10,30),color(map(scalar,-1.0,1.0,64,255)));
  // update all Pixels in one go
  canvas.updatePixels();
}

void slowCircle(PImage canvas,int x,int y,int radius,color fill){
  for(int py = y - radius; py < y + radius; py++){
    for(int px = x - radius; px < x + radius; px++){
      if(dist(x,y,px,py) < radius){
        canvas.set(px,py,fill);
      }
    }
  } 
}

void fastCircle(PImage canvas,int x,int y,int radius,color fill){
  int radiusSquared = radius * radius;
  int halfRadius = radius / 2;
  int halfRadiusSquared = halfRadius * halfRadius;
  int numPixels = canvas.pixels.length;
  //for each pixel in the ellipse bounding box
  for(int i = 0 ; i < radiusSquared; i++){
    int cx = (x - halfRadius) + (i % radius);
    int cy = (y - halfRadius) + (i / radius);
    // calculate the index within the full image
    int pixelIndex = (cx + cy * canvas.width);
    // constrain pixel index to array size bounds
    if(pixelIndex < 0) pixelIndex = 0;
    if(pixelIndex >= numPixels) pixelIndex = numPixels-1;
    // calculate the difference between circle centre and current pixel coordinates
    int dx = cx-x;
    int dy = cy-y;
    // calculate distance squared
    int distanceSquared = (dx*dx) + (dy*dy);
    // compare if the pixel is inside the circle using squared distance (a bit faster since it avoids sqrt())
    if(distanceSquared < halfRadiusSquared){
      //fill circle pixels
      canvas.pixels[pixelIndex] = fill;
    }
  }
}

值得注意的是,您可以使用PGraphics轻松地将形状光栅化为像素。

您可以看到一个有趣的PGraphics示例here

下一步要去哪里?如果您喜欢玩pixels[],并且想创建一个效果很棒的效果,而该效果可能会在CPU上运行缓慢,那么您可以考虑移到GPU上,Processing通过PShader支持它:您需要的片段着色器部分。您可以看到将基于pixels[]的CPU代码移植到GPU片段着色器here

的示例

GLSL fragment shader