1

画像上の任意のピクセルの RGB 値を 12 ビット バイナリに取得しようとしています。各チャネルは 4 ビットで表されます。たとえば、ピクセルの赤チャンネルが「255」またはバイナリ「11111111」の場合。それを「1111」に変換したいと思います。

コードは動作していますが、かなり遅いので、これを行うためのより良い方法があるかどうか疑問に思っています。

これが私がしたことです。

  1. メソッド getRGB(x, y) を使用して、1 つのピクセルの RGB 値を取得します。例: -4278864
  2. それを 3 つの別々のチャネルに変換します。たとえば、r 190 g 181 b 176
  3. それを 16 で割り、4 ビット表現に相当する整数を取得します。
  4. 数値を 2 進数に変換します。
  5. 生成されたバイナリが 4 ビット未満の場合は、バイナリの前に 0 を追加します。
  6. 12 ビット バイナリに連結して、12 ビット カラー出力を表します。例: 101110111011

ここに私のコードがあります:

import java.awt.Component;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;

public class LoadImageApp extends Component {
    private static int[] rgbArray;
    private static double bitPerColor = 4.0;

    public static void main(String[] args) {

       BufferedImage img = null;
       String fileName = "Image.jpg";

       try {
           //Read in new image file
           img = ImageIO.read(new File("src/"+fileName));
       } 
       catch (IOException e){
       }

       if (img == null) {
             System.out.println("No image loaded");
        } 
       else {

                //Get RGB Value
                int val = img.getRGB(500, 500);
                System.out.println("rgbValue from getRGB is: " + val);


                //Convert to three separate channels
                int a = (0xff000000 & val) >>> 24;
                int r = (0x00ff0000 & val) >> 16;
                int g = (0x0000ff00 & val) >> 8;
                int b = (0x000000ff & val);

                System.out.println("rgbValue in RGB is: ");
                System.out.println("a " + a + " r " + r + " g " + g + " b " + b);

                double power = Math.pow(2.0, bitPerColor);
                //Convert each channel to binary
                String r4bit = Integer.toBinaryString((int)(r/(power)));
                String g4bit = Integer.toBinaryString((int)(g/(power)));
                String b4bit = Integer.toBinaryString((int)(b/(power)));



                //Convert concatonate 0's in front to get desired bit count
                int rDifference = (int)bitPerColor - r4bit.length();
                int gDifference = (int)bitPerColor - g4bit.length();
                int bDifference = (int)bitPerColor - b4bit.length();


                for (int i = rDifference; i > 0; i--){
                    r4bit="0"+r4bit;}

                for (int i = gDifference; i > 0; i--){
                    g4bit = "0"+g4bit;}

                for (int i = bDifference; i > 0; i--){
                    b4bit = "0"+b4bit;}

                //Concatonate three channel together to form one binary
                String rgbValue = r4bit + g4bit + b4bit;

                System.out.println("rgbValue in binary is: " + rgbValue);


           }     
       }
}

必要に応じてすべて正常に動作します。ただし、1ピクセルを読み取るだけで、本当に醜く、遅く、2〜3秒かかります。コードを使用して一度に画像の一部を読み取ることを望んでいましたが、AGES を使用して画像化できます。

そのため、どんな助けでも大歓迎です。

前もって感謝します。

4

4 に答える 4

5

元のコード (16 進数) は0x00rrggbb. これを に変換し0x00000rgbます。これはそれを行います:

int rgb24 = ....;
int rgb12 = (rgb24 & 0x00f00000) >> 12 + 
            (rgb24 & 0x0000f000) >> 8  + 
            (rgb24 & 0x000000f0) >> 4;

切り捨てるのではなく、最も近い色に「丸める」場合は、次のようにします。

int r = (rgb24 & 0x00ff0000);
int g = (rgb24 & 0x0000ff00);
int b = (rgb24 & 0x000000ff);
r += (r >= 0x00f00000) ? 0x00080000 : 0;
g += (g >= 0x0000f000) ? 0x00000800 : 0;
b += (b >= 0x000000f0) ? 0x00000008 : 0;
int rgb12 = (r & 0x00f00000) >> 12 + (g & 0x0000f000) >> 8 + (b & 0x000000f0) >> 4;

これは切り上げられますが、上位 4 ビットがまだ 1111 でない場合 (オーバーフローの危険がある場合) に限ります。

于 2012-05-11T02:51:39.510 に答える
2

それを遅くしている可能性のあることがいくつかあります...

  1. から各ピクセルを個別に取得するBufferedImage
  2. Math.pow()and おそらくInteger.toBinaryString(), をループ内で複数回使用する
  3. Stringのような数字ではなく、ずっと sを使用します。が必要な場合は、最後に-->から単一の変換を行ってください。intshortStringshortString

私はおそらくこのようなことをしようとするでしょう...

// Get all the pixels
int pixelCount = imageWidth*imageHeight;
int[] pixelArray = new int[pixelCount];
img.getRGB(0,0,imageWidth,imageHeight,pixelArray,0,1);

// For storing the 4-bit data
short[] convertedArray = new short[pixelCount];

// calculate the conversion factor a single time
double power = Math.pow(2.0, bitPerColor);

// Loop over the pixels
for (int p=0;p<pixelCount;p++){
    int pixel = pixelArray[p];

    // Convert into separate channels
    int a = (0xff000000 & val) >>> 24;
    int r = (0x00ff0000 & val) >> 16;
    int g = (0x0000ff00 & val) >> 8;
    int b = (0x000000ff & val);

    // Convert to 4-bit
    a /= power;
    r /= power;
    g /= power;
    b /= power;

    // Create the short for the pixel (4 channels * 4 bits = a 2-byte short)
    short newPixel = (a & 0x0000000f) << 24 | (r & 0x0000000f) << 16 | (g & 0x0000000f) << 8 | (b & 0x0000000f);
    convertedArray[p] = newPixel;

    // If you want to have the value as a String, do it here.
    String binary = Short.toBinaryString(newPixel);
}
于 2012-05-11T02:51:03.237 に答える
0

ついでに、追加に String プラス演算子を使用していることに気付きました。私はそれが単純なコードであることを知っていますが、それがループにあるときはいくらかの作業が必要です. オペレーターはコンストラクターを呼び出して、その関数を実行します。とにかくループの大きさはどれくらいですか?

プラス演算子を使用する代わりに、おそらく StringBuilder やそれに相当する Java などの他のクラスを使用してください。最終的に使用するクラスを教えてください。コードのタイミングを計って調査してください!

考えられるボトルネックを確認したい場合は、多くのコードが実行される可能性があるため、最初にヒープまたはスタック内の LOOPS を調べます。これはどこかのコーディングルールのはずです...

試してみて、楽しんでください。私の答えに投票してください。バッジともっとポイントが必要です :-)

トミー・クウィー

于 2012-05-11T02:44:51.923 に答える