这是用java写的。我的程序的目的是采取屏幕截图的计算机屏幕多次每秒,并找到所有像素有一个特殊的阴影红色。然后,找出所有红色像素的平均位置。
为了提高图像处理的效率,我创建了3个线程,每个线程处理像素的1/4。因此,这些线程加上原始线程将处理所有像素。但是,我一直在avgLocation()方法中得到一个错误。这是一个空指针异常,我认为这是因为其他线程改变了包含所有红色像素的列表的大小,这导致程序访问一个不存在的像素的数据。为了弥补这个问题,我在Thread1上使用了.join,在Thread3 2的代码之后使用了Thread2,然后在它的代码段之后使用了.join。因此,在我调用avgLocation方法之前,所有的线程都应该连接起来,但是每当屏幕上出现特定的红色时,它仍然会给出一个NullPointerException。这是堆栈跟踪
Exception in thread "main" java.lang.NullPointerException
at Images.avgLocation(Images.java:151)
at Images.processImage(Images.java:133)
at Images.main(Images.java:169)第151行是
xSum += list.get(i)[0];第133行是我的代码:
import java.awt.AWTException;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import java.util.ArrayList;
public class Images {
//takes in an input image and a target color and a bound to check within, returns Point to target
public static Point processImage(BufferedImage img, Color color, int error) throws InterruptedException {
long start = System.nanoTime();
//bounds to check on color components, make sure all within [0,255]
int redLower = color.getRed() - error;
int redHigher = color.getRed() + error;
int greenLower = color.getGreen() - error;
int greenHigher = color.getGreen() + error;
int blueLower = color.getBlue() - error;
int blueHigher = color.getBlue() + error;
//place all components within [0,255]
if (redLower < 0) redLower = 0;
if (redHigher > 255) redHigher = 255;
if (greenLower < 0) greenLower = 0;
if (greenHigher > 255) greenHigher = 255;
if (blueLower < 0) blueLower = 0;
if (blueHigher > 255) blueHigher = 255;
//create final variables to use for thread
int redLowerF = redLower;
int redHigherF = redHigher;
int greenLowerF = greenLower;
int greenHigherF = greenHigher;
int blueLowerF = blueLower;
int blueHigherF = blueHigher;
//data of image
int[] pixels = ((DataBufferInt)img.getRaster().getDataBuffer()).getData();
int width = img.getWidth();
int height = img.getHeight();
//stores locations
ArrayList <Integer[]> locations = new ArrayList <>();
for (int i = 0; i < pixels.length/4; i++) {
int p = pixels[i];
// get red
int r = (p >> 16) & 0xff;
// get green
int g = (p >> 8) & 0xff;
// get blue
int b = p & 0xff;
//check if all components within bounds
if (r >= redLower && r<=redHigher && g>=greenLower && g <= greenHigher && b >= blueLower && b <= blueHigher) {
Integer[] point = {i % height, i/height};
locations.add(point);
}
}
Thread thread1 = new Thread( () -> {
for (int i = pixels.length/4; i < pixels.length/2; i++) {
int p = pixels[i];
// get red
int r = (p >> 16) & 0xff;
// get green
int g = (p >> 8) & 0xff;
// get blue
int b = p & 0xff;
//check if all components within bounds
if (r >= redLowerF && r<=redHigherF && g>=greenLowerF && g <= greenHigherF && b >= blueLowerF && b <= blueHigherF) {
Integer[] point = {i % height, i/height};
locations.add(point);
}
}
});
thread1.start();
Thread thread2 = new Thread( () -> {
for (int i = pixels.length/2; i < pixels.length*3/4; i++) {
int p = pixels[i];
// get red
int r = (p >> 16) & 0xff;
// get green
int g = (p >> 8) & 0xff;
// get blue
int b = p & 0xff;
//check if all components within bounds
if (r >= redLowerF && r<=redHigherF && g>=greenLowerF && g <= greenHigherF && b >= blueLowerF && b <= blueHigherF) {
Integer[] point = {i % height, i/height};
locations.add(point);
}
}
});
thread2.start();
thread1.join();
thread2.join();
Thread thread3 = new Thread( () -> {
for (int i = pixels.length*3/4; i < pixels.length; i++) {
int p = pixels[i];
// get red
int r = (p >> 16) & 0xff;
// get green
int g = (p >> 8) & 0xff;
// get blue
int b = p & 0xff;
//check if all components within bounds
if (r >= redLowerF && r<=redHigherF && g>=greenLowerF && g <= greenHigherF && b >= blueLowerF && b <= blueHigherF) {
Integer[] point = {i % height, i/height};
locations.add(point);
}
}
});
thread3.start();
thread3.join();
long end = System.nanoTime();
System.out.println((end-start)/1000000);
return avgLocation(locations);
}
//given 2D array of locations, finds average location of set and returns as point
public static Point avgLocation (ArrayList<Integer[]> list) {
//if no points in list, return an impossible point on screen
if (list.size() == 0) {
return new Point (-100, -100);
}
//coordinates of average location (set to 100 to reveal bug easily)
int avgX = 100;
int avgY = 100;
int xSum = 0;
int ySum = 0;
//loop through array
for (int i = 0; i < list.size(); i++) {
//for each location, add up coordinates
xSum += list.get(i)[0];
ySum += list.get(i)[1];
}
avgX = xSum/list.size();
avgY = ySum/list.size();
return new Point (avgX, avgY);
}
public static void main (String[] args) {
Robot robot = null;
try {
robot = new Robot();
} catch (AWTException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
while (true) {
try {
processImage(robot.createScreenCapture(new Rectangle(0,0,d.width,d.height)), new Color (255, 0, 0), 10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}发布于 2022-01-27 06:01:20
线程通过添加新元素同时修改和更改locations ArrayList。ArrayList不适合在没有同步的情况下进行这种并发修改。但是,有一些CopyOnWriteArrayList可以支持并发修改而不需要同步。
试着更换线路:
ArrayList<Integer[]> locations= new ArrayList<>();行如下:
final List<Integer []> locations = new CopyOnWriteArrayList<>();发布于 2022-01-27 06:07:25
ArrayList不是线程安全的
创建一个类似于
static private void addToList (ArrayList<Integer[]> list, Integer [] p) {
synchronized (list) {
list.add(p);
}
}可以在你的线程中调用,就像
Image.addToList(locations, point);https://stackoverflow.com/questions/70873304
复制相似问题