今回はバイト配列型の画像ではなく、ピクセル毎のRGB形式を読み取り配列にしたデータを取得する方法についてご紹介いたします。
画像の縦横のピクセル毎にループしてRGBを数値にして、配列に格納していきますが、iOSとAndroidで算出方法が異なるため、それぞれのソースについて見ていきます。
基本的には以下の図のようにRGBのデータを配列にします。
配列のイメージ
{ new[] {255, 0, 0}, //赤色
new[] { 0, 255, 0}, //緑色
new[] { 0, 0, 255}, //青色
new[] {255, 255, 0}, //黄色
new[] {255, 0, 255}, //桃色
new[] { 0, 255, 255}, //水色
new[] {255, 255, 255}, //白色
new[] {123, 123, 123}, //灰色
new[] { 0, 0, 0}} //黒色
前提条件
・Windows10 Pro 64Bit
・Visual Studio 2015 Community Update3
・Xamarin 4.3.0.795 (NuGet Xamarin.Forms 2.3.4.270)
・macOS Sierra 10.12.4 / Xcode8.3.1 / Xamarin.iOS 10.6.0.10
1.Androidの実装方法
2019/03/12 追記
コメント欄でご指摘いただいた方法で多重ループによるパフォーマンスの低下を解消できる方法に変更しました。
念のため、多重ループの古いソースを10回繰り返した場合と、GetPixcelsで取得する方法を10回繰り返した場合でパフォーマンスを計測してみましたところ、多重ループが2090ミリ秒。GetPixcelsが192ミリ秒でした。1回あたりで190ミリ秒程パフォーマンスに差がありました。(※尚、検証では小さいQRコードの画像を読み込んでみましたが大きな差となっています。)
using System.Collections.Generic;
public class ImageService
{
/// <summary>
/// 画像からピクセル毎のRGB配列を取得する
/// </summary>
/// <param name="image"></param>
/// <returns></returns>
public static byte[] GetRgbBytes(Bitmap image)
{
//var rgbBytes = new List<byte>();
//for (int y = 0; y < image.Height; y++)
//{
// for (int x = 0; x < image.Width; x++)
// {
// var c = new Android.Graphics.Color(image.GetPixel(x, y));
//
// rgbBytes.AddRange(new[] { c.R, c.G, c.B });
// }
//}
//2019/03/12 コメント欄でご指摘いただきました方法に変更しました。
var rgbBytes = new List<byte>();
var pixels = new int[image.Width * image.Height];
image.GetPixels(pixels, 0, image.Width, 0, 0, image.Width, image.Height);
foreach (var argb in pixels)
{
var c = new Android.Graphics.Color(argb);
rgbBytes.AddRange(new[] { c.R, c.G, c.B });
}
return rgbBytes.ToArray();
}
}
2.iOSの実装方法
using System.Collections.Generic;
using UIKit;
using CoreGraphics;
public class ImageService
{
/// <summary>
/// 画像からピクセル毎のRGB配列を取得する
/// </summary>
/// <param name="image"></param>
/// <returns></returns>
public static byte[] GetRgbBytes(UIImage image)
{
var rgbBytes = new List<byte>();
// First get the image into your data buffer
CGImage imageRef = image.CGImage;
int width = (int)image.Size.Width;
int height = (int)image.Size.Height;
CGColorSpace colorSpace = CGColorSpace.CreateDeviceRGB();
byte[] rawData = new byte[height * width * 4];
int bytesPerPixel = 4;
int bytesPerRow = bytesPerPixel * width;
int bitsPerComponent = 8;
CGContext context = new CGBitmapContext(rawData, width, height,
bitsPerComponent, bytesPerRow, colorSpace,
CGBitmapFlags.PremultipliedLast | CGBitmapFlags.ByteOrder32Big);
context.DrawImage(new CGRect(0, 0, width, height), imageRef);
// Now your rawData contains the image data in the RGBA8888 pixel format.
nint byteIndex = 0;
for (int i = 0; i < height * width; i++)
{
byte red = rawData[byteIndex];
byte green = rawData[byteIndex + 1];
byte blue = rawData[byteIndex + 2];
byte alpha = rawData[byteIndex + 3];
byteIndex += bytesPerPixel;
rgbBytes.AddRange(new[] { red, green, blue });
}
return rgbBytes.ToArray();
}
}
最後までお読みいただきありがとうございます。
当ブログの内容をまとめた Xamarin逆引きメニュー は以下のURLからご覧になれます。
https://itblog.dynaspo.com/blog-entry-81.html