public RGBImage process(Scene scene, int nthread) throws InterruptedException {
		RGBImage image = new RGBImage(nCol, nRow);
		if (antialias == 0) {
			double dx = width / nCol;
			double dy = height / nRow;
			ArrayList<PixelEval> pixelEvals = new ArrayList<PixelEval>(nRow * nCol);
			for (int row = 0; row < nRow; row += 4) {
				pixelEvals.add(new PixelEval(scene, image, row, Math.min(nRow,  row + 4), 0, nCol, dx, dy));
			}
			ExecutorService pool = Executors.newFixedThreadPool(nthread);
			pool.invokeAll(pixelEvals);
			return image;
		}
		int n = antialias;
		int nr = n * nRow + 1;
		int nc = n * nCol + 1;
		double dx = width / (n * nCol);
		double dy = 1.0 / (n * nRow);
		double w = 1.0 / (n * n);
		RGBImage ximage = new RGBImage(nc, nr);
		ArrayList<PixelEval> pixelEvals = new ArrayList<PixelEval>(nRow * nCol);
		for (int row = 0; row < nr; row++) {
			pixelEvals.add(new PixelEval(scene, ximage, row, row + 1, 0, nc, dx, dy));
		}
		ExecutorService pool = Executors.newFixedThreadPool(nthread);
		pool.invokeAll(pixelEvals);
		for (int row = 0; row < nRow; row++) {
			for (int col = 0; col < nCol; col++) {
				int c0 = n * col;
				int r0 = n * row;
				Color color = new Color(0, 0, 0);
				for (int r = 0; r <= n; r++) {
					for (int c = 0; c <= n; c++) {
						Color x = ximage.getPixel(c0 + c, r0 + r);
						double wr = (r == 0 || r == n) ? 0.5 : 1.0;
						double wc = (c == 0 || c == n) ? 0.5 : 1.0;
						double wx = w * wr * wc;
						color = color.add(x.mult(wx));
					}
				}
				image.setPixel(col, row, color);
			}
		}
		return image;
	}