从图像字节数组中提取然后堆叠高字节和低字节
Extract then stack the high and low bytes from an array of image bytes
我对字节级别的图像压缩比较陌生,目前正在研究 java 图像预处理器,它将获取 bmp 图像,将其转换为 8 位无符号灰度,然后在导出和压缩之前根据高低堆叠其字节。经过广泛的研究和测试各种字节提取方法后,我仍然没有看到我需要的结果。在我继续之前,应该注意所有这些图像最初都是 DICOM 格式,我正在使用 ij.plugin.DICOM 包将像素数据提取为 bmp 图像。
下面的描述用下面的代码表示。目前,我正在将原始图像作为缓冲图像读取,将其转换为灰度,然后从光栅中获取图像字节。然后我获取这些字节,并使用我在 Whosebug 上找到的一些其他代码并将它们 "converting" 转换为二进制位的字符串表示形式。然后我将该字符串发送到字符数组。下一步可能是无关紧要的,但我想在删除它之前获得您的意见(因为我是新手)。我制作了一个 Bitset 并遍历 "binary" 字符数组。如果字符值为“1”,我将 BitSet 中的那个位置设置为 true。然后我将 BitSet 发送到另一个字节数组。
然后我创建了两个新的字节数组,一个用于高字节,一个用于低字节。使用 for 循环,我遍历 "bit" 数组并将每 4 个 "bits" 存储在高字节或低字节中,具体取决于我们在数组中的位置。
最后,我获取 DICOM 标签数据,从中创建一个字节数组,然后将标签数组、高字节数组和低字节数组堆叠在一起。我的预期结果是使图像矩阵为 "split",上半部分包含所有高字节,下半部分包含所有低字节。有人告诉我标签字节非常小,它们不应该影响最终结果(我已经在没有它们的情况下测试了图像,只是为了确定,并且没有明显的差异)。
下面是代码。如果您有任何问题,请告诉我,我会相应地修改我的post。我试图包括所有相关数据。如果您需要更多,请告诉我。
BufferedImage originalImage = getGrayScale(img.getBufferedImage());//returns an 8-bit unsigned grayscale conversion of the original image
byte[] imageInByte = ((DataBufferByte) originalImage.getRaster().getDataBuffer()).getData();
String binary = toBinary(imageInByte); //converts to a String representation of the binary bits
char[] binCharArray = binary.toCharArray();
BitSet bits = new BitSet(binCharArray.length);
for (int i = 0; i < binCharArray.length; i++) {
if (binCharArray[i] == '1') {
bits.set(i);
}
}
imageInByte = bits.toByteArray();
byte[] high = new byte[(int) imageInByte.length/2];
byte[] low = new byte[(int) imageInByte.length/2];
int highC = 0;
int lowC = 0;
boolean change = false; //start out storing in the high bit
//change will = true on very first run. While true, load in the high byte array. Else low byte
for(int i = 0; i < imageInByte.length; i++){
if(i % 4 == 0){
change = !change;
}
if(change){
high[highC] = imageInByte[i];
highC++;
} else {
low[lowC] = imageInByte[i];
lowC++;
}
}
//old code from a previous attempt.
// for (int j = 0; j < imageInByte.length; j++) {
// byte h = (byte) (imageInByte[j] & 0xFF);
// byte l = (byte) ((imageInByte[j] >> 8) & 0xFF);
// high[j] = h;
// low[j] = l;
// }
OutputStream out = null;
//add this array to the image array. It goes at the beginning.
byte[] tagBytes = dicomTags.getBytes();
currProcessingImageTagLength = tagBytes.length;
imageInByte = new byte[high.length + low.length + tagBytes.length];
System.arraycopy(tagBytes, 0, imageInByte, 0, tagBytes.length);
System.arraycopy(high, 0, imageInByte, tagBytes.length, high.length);
System.arraycopy(low, 0, imageInByte, tagBytes.length + high.length, low.length);
BufferedImage bImageFromConvert = new BufferedImage(dimWidth, dimHeight, BufferedImage.TYPE_BYTE_GRAY);//dimWidth and dimHeight are the image dimensions, stored much earlier in this function
byte[] bufferHolder = ((DataBufferByte) bImageFromConvert.getRaster().getDataBuffer()).getData();
System.arraycopy(imageInByte, 0, bufferHolder, 0, bufferHolder.length);
//This is where I try and write the final image before sending it off to an image compressor
ImageIO.write(bImageFromConvert, "bmp", new File(
directory + fileName + "_Compressed.bmp"));
return new File(directory + fileName + "_Compressed.bmp");
下面是 toBinary 函数,如果您感兴趣的话:
private static String toBinary(byte[] bytes) {
StringBuilder sb = new StringBuilder(bytes.length * Byte.SIZE);
for (int i = 0; i < Byte.SIZE * bytes.length; i++) {
sb.append((bytes[i / Byte.SIZE] << i % Byte.SIZE & 0x80) == 0 ? '0' : '1');
}
return sb.toString();
}
非常感谢您的帮助!我现在已经花了将近 20 个小时来解决这个问题。这是一个巨大的头痛,如果您有任何见解,我们将不胜感激。
编辑:这是 getGreyScale 函数:
public static BufferedImage getGrayScale(BufferedImage inputImage) {
BufferedImage img = new BufferedImage(inputImage.getWidth(), inputImage.getHeight(), BufferedImage.TYPE_BYTE_GRAY);
Graphics g = img.getGraphics();
g.drawImage(inputImage, 0, 0, null);
g.dispose();
return img;
}
编辑 2:我应要求添加了一些图片。
当前输出:
current image
注意,由于我的声誉低于 10,我不能 post 具有 "expected" 高字节和低字节结果的图像。
这表示每 4 个字节变化一次;那不是你想要的:
for(int i = 0; i < imageInByte.length; i++){
if(i % 4 == 0){
change = !change;
}
if(change){
high[highC] = imageInByte[i];
highC++;
} else {
low[lowC] = imageInByte[i];
lowC++;
}
}
我会用你之前的尝试替换它
for (int j = 0; j < imageInByte.length; j+=2) {
byte h = (byte) (imageInByte[j] & 0xF0);
byte h2 = (byte) (imageInByte[j+1] & 0xF0);
byte l = (byte) (imageInByte[j] & 0x0f);
byte l2 = (byte) (imageInByte[j+1] & 0x0f);
high[j/2] = h|(h2>>4);
low[j/2] = (l<<4)|l2;
}
我对字节级别的图像压缩比较陌生,目前正在研究 java 图像预处理器,它将获取 bmp 图像,将其转换为 8 位无符号灰度,然后在导出和压缩之前根据高低堆叠其字节。经过广泛的研究和测试各种字节提取方法后,我仍然没有看到我需要的结果。在我继续之前,应该注意所有这些图像最初都是 DICOM 格式,我正在使用 ij.plugin.DICOM 包将像素数据提取为 bmp 图像。
下面的描述用下面的代码表示。目前,我正在将原始图像作为缓冲图像读取,将其转换为灰度,然后从光栅中获取图像字节。然后我获取这些字节,并使用我在 Whosebug 上找到的一些其他代码并将它们 "converting" 转换为二进制位的字符串表示形式。然后我将该字符串发送到字符数组。下一步可能是无关紧要的,但我想在删除它之前获得您的意见(因为我是新手)。我制作了一个 Bitset 并遍历 "binary" 字符数组。如果字符值为“1”,我将 BitSet 中的那个位置设置为 true。然后我将 BitSet 发送到另一个字节数组。
然后我创建了两个新的字节数组,一个用于高字节,一个用于低字节。使用 for 循环,我遍历 "bit" 数组并将每 4 个 "bits" 存储在高字节或低字节中,具体取决于我们在数组中的位置。
最后,我获取 DICOM 标签数据,从中创建一个字节数组,然后将标签数组、高字节数组和低字节数组堆叠在一起。我的预期结果是使图像矩阵为 "split",上半部分包含所有高字节,下半部分包含所有低字节。有人告诉我标签字节非常小,它们不应该影响最终结果(我已经在没有它们的情况下测试了图像,只是为了确定,并且没有明显的差异)。
下面是代码。如果您有任何问题,请告诉我,我会相应地修改我的post。我试图包括所有相关数据。如果您需要更多,请告诉我。
BufferedImage originalImage = getGrayScale(img.getBufferedImage());//returns an 8-bit unsigned grayscale conversion of the original image
byte[] imageInByte = ((DataBufferByte) originalImage.getRaster().getDataBuffer()).getData();
String binary = toBinary(imageInByte); //converts to a String representation of the binary bits
char[] binCharArray = binary.toCharArray();
BitSet bits = new BitSet(binCharArray.length);
for (int i = 0; i < binCharArray.length; i++) {
if (binCharArray[i] == '1') {
bits.set(i);
}
}
imageInByte = bits.toByteArray();
byte[] high = new byte[(int) imageInByte.length/2];
byte[] low = new byte[(int) imageInByte.length/2];
int highC = 0;
int lowC = 0;
boolean change = false; //start out storing in the high bit
//change will = true on very first run. While true, load in the high byte array. Else low byte
for(int i = 0; i < imageInByte.length; i++){
if(i % 4 == 0){
change = !change;
}
if(change){
high[highC] = imageInByte[i];
highC++;
} else {
low[lowC] = imageInByte[i];
lowC++;
}
}
//old code from a previous attempt.
// for (int j = 0; j < imageInByte.length; j++) {
// byte h = (byte) (imageInByte[j] & 0xFF);
// byte l = (byte) ((imageInByte[j] >> 8) & 0xFF);
// high[j] = h;
// low[j] = l;
// }
OutputStream out = null;
//add this array to the image array. It goes at the beginning.
byte[] tagBytes = dicomTags.getBytes();
currProcessingImageTagLength = tagBytes.length;
imageInByte = new byte[high.length + low.length + tagBytes.length];
System.arraycopy(tagBytes, 0, imageInByte, 0, tagBytes.length);
System.arraycopy(high, 0, imageInByte, tagBytes.length, high.length);
System.arraycopy(low, 0, imageInByte, tagBytes.length + high.length, low.length);
BufferedImage bImageFromConvert = new BufferedImage(dimWidth, dimHeight, BufferedImage.TYPE_BYTE_GRAY);//dimWidth and dimHeight are the image dimensions, stored much earlier in this function
byte[] bufferHolder = ((DataBufferByte) bImageFromConvert.getRaster().getDataBuffer()).getData();
System.arraycopy(imageInByte, 0, bufferHolder, 0, bufferHolder.length);
//This is where I try and write the final image before sending it off to an image compressor
ImageIO.write(bImageFromConvert, "bmp", new File(
directory + fileName + "_Compressed.bmp"));
return new File(directory + fileName + "_Compressed.bmp");
下面是 toBinary 函数,如果您感兴趣的话:
private static String toBinary(byte[] bytes) {
StringBuilder sb = new StringBuilder(bytes.length * Byte.SIZE);
for (int i = 0; i < Byte.SIZE * bytes.length; i++) {
sb.append((bytes[i / Byte.SIZE] << i % Byte.SIZE & 0x80) == 0 ? '0' : '1');
}
return sb.toString();
}
非常感谢您的帮助!我现在已经花了将近 20 个小时来解决这个问题。这是一个巨大的头痛,如果您有任何见解,我们将不胜感激。
编辑:这是 getGreyScale 函数:
public static BufferedImage getGrayScale(BufferedImage inputImage) {
BufferedImage img = new BufferedImage(inputImage.getWidth(), inputImage.getHeight(), BufferedImage.TYPE_BYTE_GRAY);
Graphics g = img.getGraphics();
g.drawImage(inputImage, 0, 0, null);
g.dispose();
return img;
}
编辑 2:我应要求添加了一些图片。
当前输出:
current image
注意,由于我的声誉低于 10,我不能 post 具有 "expected" 高字节和低字节结果的图像。
这表示每 4 个字节变化一次;那不是你想要的:
for(int i = 0; i < imageInByte.length; i++){
if(i % 4 == 0){
change = !change;
}
if(change){
high[highC] = imageInByte[i];
highC++;
} else {
low[lowC] = imageInByte[i];
lowC++;
}
}
我会用你之前的尝试替换它
for (int j = 0; j < imageInByte.length; j+=2) {
byte h = (byte) (imageInByte[j] & 0xF0);
byte h2 = (byte) (imageInByte[j+1] & 0xF0);
byte l = (byte) (imageInByte[j] & 0x0f);
byte l2 = (byte) (imageInByte[j+1] & 0x0f);
high[j/2] = h|(h2>>4);
low[j/2] = (l<<4)|l2;
}