创建要写入文件的 PPM 图像 Java
Creating a PPM Image to be Written to a File Java
所以我正在开发 java 中的一个程序,它创建一个矩形图像(请参阅下面的 link)作为 ppm 图像,该图像将进一步写入 ppm 文件。创建图像并将图像写入我得到的文件。但是,我很难动态创建图像以使其适用于指定的任何宽度和高度。据我了解,p3 ppm 文件仅遵循以下格式的 4x4 图像。
P3
4 4
15
0 0 0 0 0 0 0 0 0 15 0 15
0 0 0 0 15 7 0 0 0 0 0 0
0 0 0 0 0 0 0 15 7 0 0 0
15 0 15 0 0 0 0 0 0 0 0 0
其中前三个数字是标题,其余只是每个像素的 rgb 值。但是我无法弄清楚如何为下面的图像和指定的任何尺寸创建上面的矩阵,因为它不包括直线中的纯色?
要创建的图像:
我想我可以创建一个数组列表,它包含一个 rgb 值数组,这样列表中的每个索引都是一个 rgb 集,然后是右边的下一个 rgb 集。但是,我对 rgb 值是多少感到很困惑。这是我拥有的:
public static void createImage(int width, int height){
pic = new ArrayList();
int[] rgb = new int[3];
for(int i = 0; i <= width; i++){
for(int j = 0; i <= height; j++){
rgb[0] = 255-j; //random values as im not sure what they should be or how to calculate them
rgb[1] = 0+j;
rgb[1] = 0+j;
pic.add(rgb);
}
}
}
提前致谢。
编辑::更新代码
我已经设法解决了大部分问题,但是,生成的图像与上面发布的图像不匹配。使用此代码。我得到以下图像:
package ppm;
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
public class PPM {
private BufferedImage img;
private static final String imageDir = "Image/rect.ppm";
private final static String filename = "assignment1_q1.ppm";
private static byte bytes[]=null; // bytes which make up binary PPM image
private static double doubles[] = null;
private static int height = 0;
private static int width = 0;
private static ArrayList pic;
private static String matrix="";
/**
* @param args the command line arguments
*/
public static void main(String[] args) throws IOException {
createImage(200, 200);
writeImage(filename);
}
public static void createImage(int width, int height){
pic = new ArrayList();
int[] rgb = new int[3];
matrix +="P3\n" + width + "\n" + height + "\n255\n";
for(int i = 0; i <= height; i++){
for(int j = 0; j <= width; j++){
Color c = getColor(width, height, j, i);
//System.out.println(c);
if(c==Color.red){
rgb[0] = (int) (255*factor(width, height, j, i));
rgb[1] = 0;
rgb[2] = 0;
}else if(c==Color.green){
rgb[0] = 0;
rgb[1] = (int) (255*factor(width, height, j, i));
rgb[2] = 0;
}else if(c==Color.blue){
rgb[0] = 0;
rgb[1] = 0;
rgb[2] = (int) (255*factor(width, height, j, i));
}else if(c== Color.white){
rgb[0] = (int) (255*factor(width, height, j, i));
rgb[1] = (int) (255*factor(width, height, j, i));
rgb[2] = (int) (255*factor(width, height, j, i));
}
matrix += ""+ rgb[0] + " " + rgb[1] + " " + rgb[2] + " " ;
//System.out.println(""+ rgb[0] + " " + rgb[1] + " " + rgb[2] + " ");
//pic.add(rgb);
}
matrix += "\n";
}
}
public static Color getColor(int width, int height, int a, int b){
double d1 = ((double) width / height) * a;
double d2 = (((double) -width / height) * a + height);
if(d1 > b && d2 > b) return Color.green;
if(d1 > b && d2 < b) return Color.blue;
if(d1 < b && d2 > b) return Color.red;
return Color.white;
}
public static double factor(int width, int height, int a, int b){
double factorX = (double) Math.min(a, width - a) / width * 2;
double factorY = (double) Math.min(b, height - b) / height * 2;
//System.out.println(Math.min(factorX, factorY));
return Math.min(factorX, factorY);
}
public static void writeImage(String fn) throws FileNotFoundException, IOException {
//if (pic != null) {
FileOutputStream fos = new FileOutputStream(fn);
fos.write(new String(matrix).getBytes());
//fos.write(data.length);
//System.out.println(data.length);
fos.close();
// }
}
}
您可以使用Linear functions对图片中的对角线进行建模。请记住,坐标 (0, 0)
位于图像的 top-left 角!
假设您要创建尺寸为 width
和 height
的图像,从 top-left 到 bottom-right 的对角线将穿过点 (0, 0)
和 (width, height)
:
y = ax + t
0 = a * 0 + t => t = 0
height = a * width + 0 => a = height / width
d1(x) = (height / width) * x
现在我们可以计算第二条对角线的函数了。这条对角线穿过点 (0, height)
和 (width, 0)
,所以:
y = ax + t
height = a * 0 + t => t = height
0 = a * width + height => a = -(height/width)
d2(x) = -(height/width) * x + height
据此我们可以确定图像中的某个点是在对角线下方还是上方。以点(a, b)
:
为例
if d1(a) > b
: (a, b) 位于第一条对角线(left-top 到 right-bottom)之上,因此它必须是蓝色或绿色。否则它必须是红色或白色
if d2(a) > b
: (a, b) 位于第二对角线之上,因此它必须是红色或绿色。否则必须是白色或蓝色
通过应用这两种关系,很容易确定某个点属于四种颜色中的哪一种:
Color getColor(int width, int height, int a, int b){
double d1 = ((double) height / width) * a;
double d2 = ((double) -height / width) * a + height;
if(d1 > b && d2 > b) return greenColor;
if(d1 > b && d2 < b) return blueColor;
if(d1 < b && d2 > b) return redColor;
return whiteColor;
}
现在还有最后一件事我们需要考虑:图像向其边界变暗。
可以通过将每个通道乘以一个因子来创建颜色的较暗版本。系数越低,得到的颜色越深。为了简单起见,我假设亮度的变化从图像的中心开始是线性的。
由于亮度沿两个轴独立变化,我们需要通过计算沿两个轴的变化并使用最大值对其进行建模。
可以使用到图像较近边界的距离与到中心的距离(仅在一个轴上)的关系来模拟作为中心距离函数的亮度变化:
deltaX = min(a, width - a) / (width / 2)
deltaY = min(b, height - b) / (height / 2)
所以我们可以这样得到乘以每个color-channel的因数:
double factor(int width, int height, int a, int b){
double factorX = (double) Math.min(a, width - a) / width * 2;
double factorY = (double) Math.min(b, height - b) / height * 2;
return Math.min(factorX, factorY);
}
所以我正在开发 java 中的一个程序,它创建一个矩形图像(请参阅下面的 link)作为 ppm 图像,该图像将进一步写入 ppm 文件。创建图像并将图像写入我得到的文件。但是,我很难动态创建图像以使其适用于指定的任何宽度和高度。据我了解,p3 ppm 文件仅遵循以下格式的 4x4 图像。
P3
4 4
15
0 0 0 0 0 0 0 0 0 15 0 15
0 0 0 0 15 7 0 0 0 0 0 0
0 0 0 0 0 0 0 15 7 0 0 0
15 0 15 0 0 0 0 0 0 0 0 0
其中前三个数字是标题,其余只是每个像素的 rgb 值。但是我无法弄清楚如何为下面的图像和指定的任何尺寸创建上面的矩阵,因为它不包括直线中的纯色?
要创建的图像:
我想我可以创建一个数组列表,它包含一个 rgb 值数组,这样列表中的每个索引都是一个 rgb 集,然后是右边的下一个 rgb 集。但是,我对 rgb 值是多少感到很困惑。这是我拥有的:
public static void createImage(int width, int height){
pic = new ArrayList();
int[] rgb = new int[3];
for(int i = 0; i <= width; i++){
for(int j = 0; i <= height; j++){
rgb[0] = 255-j; //random values as im not sure what they should be or how to calculate them
rgb[1] = 0+j;
rgb[1] = 0+j;
pic.add(rgb);
}
}
}
提前致谢。
编辑::更新代码 我已经设法解决了大部分问题,但是,生成的图像与上面发布的图像不匹配。使用此代码。我得到以下图像:
package ppm;
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
public class PPM {
private BufferedImage img;
private static final String imageDir = "Image/rect.ppm";
private final static String filename = "assignment1_q1.ppm";
private static byte bytes[]=null; // bytes which make up binary PPM image
private static double doubles[] = null;
private static int height = 0;
private static int width = 0;
private static ArrayList pic;
private static String matrix="";
/**
* @param args the command line arguments
*/
public static void main(String[] args) throws IOException {
createImage(200, 200);
writeImage(filename);
}
public static void createImage(int width, int height){
pic = new ArrayList();
int[] rgb = new int[3];
matrix +="P3\n" + width + "\n" + height + "\n255\n";
for(int i = 0; i <= height; i++){
for(int j = 0; j <= width; j++){
Color c = getColor(width, height, j, i);
//System.out.println(c);
if(c==Color.red){
rgb[0] = (int) (255*factor(width, height, j, i));
rgb[1] = 0;
rgb[2] = 0;
}else if(c==Color.green){
rgb[0] = 0;
rgb[1] = (int) (255*factor(width, height, j, i));
rgb[2] = 0;
}else if(c==Color.blue){
rgb[0] = 0;
rgb[1] = 0;
rgb[2] = (int) (255*factor(width, height, j, i));
}else if(c== Color.white){
rgb[0] = (int) (255*factor(width, height, j, i));
rgb[1] = (int) (255*factor(width, height, j, i));
rgb[2] = (int) (255*factor(width, height, j, i));
}
matrix += ""+ rgb[0] + " " + rgb[1] + " " + rgb[2] + " " ;
//System.out.println(""+ rgb[0] + " " + rgb[1] + " " + rgb[2] + " ");
//pic.add(rgb);
}
matrix += "\n";
}
}
public static Color getColor(int width, int height, int a, int b){
double d1 = ((double) width / height) * a;
double d2 = (((double) -width / height) * a + height);
if(d1 > b && d2 > b) return Color.green;
if(d1 > b && d2 < b) return Color.blue;
if(d1 < b && d2 > b) return Color.red;
return Color.white;
}
public static double factor(int width, int height, int a, int b){
double factorX = (double) Math.min(a, width - a) / width * 2;
double factorY = (double) Math.min(b, height - b) / height * 2;
//System.out.println(Math.min(factorX, factorY));
return Math.min(factorX, factorY);
}
public static void writeImage(String fn) throws FileNotFoundException, IOException {
//if (pic != null) {
FileOutputStream fos = new FileOutputStream(fn);
fos.write(new String(matrix).getBytes());
//fos.write(data.length);
//System.out.println(data.length);
fos.close();
// }
}
}
您可以使用Linear functions对图片中的对角线进行建模。请记住,坐标 (0, 0)
位于图像的 top-left 角!
假设您要创建尺寸为 width
和 height
的图像,从 top-left 到 bottom-right 的对角线将穿过点 (0, 0)
和 (width, height)
:
y = ax + t
0 = a * 0 + t => t = 0
height = a * width + 0 => a = height / width
d1(x) = (height / width) * x
现在我们可以计算第二条对角线的函数了。这条对角线穿过点 (0, height)
和 (width, 0)
,所以:
y = ax + t
height = a * 0 + t => t = height
0 = a * width + height => a = -(height/width)
d2(x) = -(height/width) * x + height
据此我们可以确定图像中的某个点是在对角线下方还是上方。以点(a, b)
:
if d1(a) > b
: (a, b) 位于第一条对角线(left-top 到 right-bottom)之上,因此它必须是蓝色或绿色。否则它必须是红色或白色if d2(a) > b
: (a, b) 位于第二对角线之上,因此它必须是红色或绿色。否则必须是白色或蓝色
通过应用这两种关系,很容易确定某个点属于四种颜色中的哪一种:
Color getColor(int width, int height, int a, int b){
double d1 = ((double) height / width) * a;
double d2 = ((double) -height / width) * a + height;
if(d1 > b && d2 > b) return greenColor;
if(d1 > b && d2 < b) return blueColor;
if(d1 < b && d2 > b) return redColor;
return whiteColor;
}
现在还有最后一件事我们需要考虑:图像向其边界变暗。
可以通过将每个通道乘以一个因子来创建颜色的较暗版本。系数越低,得到的颜色越深。为了简单起见,我假设亮度的变化从图像的中心开始是线性的。
由于亮度沿两个轴独立变化,我们需要通过计算沿两个轴的变化并使用最大值对其进行建模。
可以使用到图像较近边界的距离与到中心的距离(仅在一个轴上)的关系来模拟作为中心距离函数的亮度变化:
deltaX = min(a, width - a) / (width / 2)
deltaY = min(b, height - b) / (height / 2)
所以我们可以这样得到乘以每个color-channel的因数:
double factor(int width, int height, int a, int b){
double factorX = (double) Math.min(a, width - a) / width * 2;
double factorY = (double) Math.min(b, height - b) / height * 2;
return Math.min(factorX, factorY);
}