OpenCVの本を読み学習中です。
しかし、よくわからん。。。切羽詰まったので本当に基礎からやり直していく方向です。
画像データとは
参考にするサイトはこちらです。
とりあえずわかっているのは画像データが下のようなものだということ。ちなみに下のイメージです。(32x32)のPNGファイル
早い話が、RGBのデータとRGBAのデータがあり透過したい場合はRGBAのデータでないとできない。。。
というわけです。
具体的に、自分の場合はデータを操作するために、以下のような経緯で理解しました。
画像の生データを見る
[x: 255.0 y: 255.0],[x: 255.0 y: 255.0],[x: 255.0 y: 255.0],[x: 255.0 y: 255.0],[x: 255.0 y: 255.0],[x: 255.0 y: 255.0],[x: 255.0 y: 255.0],[x: 255.0 y: 255.0],[x: 255.0 y: 255.0],[x: 255.0 y: 255.0],[x: 255.0 y: 255.0],[x: 255.0 y: 255.0],[x: 255.0 y: 255.0],[x: 255.0 y: 255.0],[x: 255.0 y: 255.0],[x: 255.0 y: 255.0],[x: 255.0 y: 255.0],[x: 255.0 y: 255.0],[x: 255.0 y: 255.0],[x: 255.0 y: 255.0],[x: 255.0 y: 255.0],[x: 255.0 y: 255.0],[x: 255.0 y: 255.0],[x: 255.0 y: 255.0],[x: 255.0 y: 255.0],[x: 255.0 y: 255.0],[x: 255.0 y: 255.0],[x: 255.0 y: 255.0],[x: 255.0 y: 255.0],[x: 255.0 y: 255.0],[x: 255.0 y: 255.0],[x: 255.0 y: 255.0]
....
こんな風になっていて「わけわからん!」と思っていたが、
中身を System.out.println()
して見ると
// 表示イメージを読み取る
Mat charactor = Imgcodecs.imread(url.getPath(), Imgcodecs.IMREAD_COLOR);
Mat charactor1 = Imgcodecs.imread(url.getPath(), Imgcodecs.IMREAD_UNCHANGED);
System.out.println("Channels = channelA: " + charactor.channels() + " channelB: " + charactor1.channels());
System.out.println("Length = channelA: " + charactor.get(0, 0).length + " channelB: " + charactor1.get(0, 0).length);
System.out.println("Byte1 = channelA: " + charactor.get(5, 24)[0] + " channelB: " + charactor1.get(6, 24)[0]);
System.out.println("Byte last = channelA: " + charactor.get(5, 24)[2] + " channelB: " + charactor1.get(6, 24)[3]);
こんな感じのコードで出力してみたところ。。。
Channels = channelA: 3 channelB: 4
Length = channelA: 3 channelB: 4
Byte1 = channelA: 33.0 channelB: 84.0
Byte last = channelA: 83.0 channelB: 255.0
上のように出力されたました。
つまり
RGBのファイルだと、Mat = (R, G, B) = (xx.xx, xx.xx, xx.xx)
という値が入っている
RGBA(透明度付き)の場合だとMat = (R, G, B, A) = (xx.xx, xx.xx, xx.xx, xx.xx)
具体的には、
Mat charactor = Imgcodecs.imread(url.getPath(), Imgcodecs.IMREAD_COLOR);
double[] d = characotr.get(0, 0); // 画像行列(32x32)の左端
d[0]; // Rの値
d[1]; // Gの値
d[2]; // Bの値
d[3]; // Aの値
という風になる。。。
そして、このことを理解してプログラムを実行すると
取得したイメージファイルのRの値が255のデータ(下の画像の白い部分(255,255,255))のアルファ値を0にセットしてやれば、データの背景を透過することができる。。。
ちょっと小さいけど、右側のイメージは背景が透過されています。
実行したコードはいか下です。
// 表示するイメージを取得
URL url = getClass().getResource("/pipo-charachip001.png");
// 表示イメージを読み取る
// RGBで読み取る
Mat charactor = Imgcodecs.imread(url.getPath(), Imgcodecs.IMREAD_COLOR);
// RGBAで読み取る
Mat charactor1 = Imgcodecs.imread(url.getPath(), Imgcodecs.IMREAD_UNCHANGED);
System.out.println("Channels = channelA: " + charactor.channels() + " channelB: " + charactor1.channels());
System.out.println("Length = channelA: " + charactor.get(0, 0).length + " channelB: " + charactor1.get(0, 0).length);
System.out.println("Byte1 = channelA: " + charactor.get(5, 24)[0] + " channelB: " + charactor1.get(6, 24)[0]);
System.out.println("Byte last = channelA: " + charactor.get(5, 24)[2] + " channelB: " + charactor1.get(6, 24)[3]);
boolean boo = true;
for (int y = 0; y < charactor1.height(); y++) {
for (int x = 0; x < charactor1.width(); x++) {
double[] d = charactor1.get(y, x);
if (d[0] == 255.0) {
if (boo) {
System.out.println("*** Testing ***");
boo = false;
}
d[3] = 0.0;
charactor1.put(y, x, d);
}
}
}
System.out.println("Byte last = channelA: " + charactor.get(5, 24)[2] + " channelB: " + charactor1.get(6, 24)[3]);
MatOfByte b = new MatOfByte();
Imgcodecs.imencode(".png", charactor, b);
BufferedImage out = createImage(b);
drawBufferedImage(out, before);
MatOfByte c = new MatOfByte();
Imgcodecs.imencode(".png", charactor1, c);
BufferedImage out1 = createImage(c);
drawBufferedImage(out1, after);
出力したコンソールはいかです。
ポイント
取得したdouble型のデータをMatクラスにセットする方法は以下のようにやりました。
// Mat charactor1 = Imgcodecs.imread(url.getPath(), Imgcodecs.IMREAD_UNCHANGED); double[] d = charactor1.get(y, x); d[3] = 0.0; charactor1.put(y, x, d);
こんな感じで、できました。