fc2ブログ

記事一覧

画像データからピクセル毎のRGB配列を取得する方法 | Xamarin.Forms


今回はバイト配列型の画像ではなく、ピクセル毎のRGB形式を読み取り配列にしたデータを取得する方法についてご紹介いたします。
画像の縦横のピクセル毎にループしてRGBを数値にして、配列に格納していきますが、iOSとAndroidで算出方法が異なるため、それぞれのソースについて見ていきます。
基本的には以下の図のようにRGBのデータを配列にします。

xamarin_rgb_array_01.png


配列のイメージ
{ 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


関連記事

コメント

Re: Androidの実装方法について
コメントありがとうございます。
並びに確認不足で申し訳ございません。

GetPixelよりも配列で取得できるGetPixelsの方が当然パフォーマンス的には勝っていますね。
その存在については調査不足でした。勉強になります。
動作を確認してみましたところ、取得される結果にも問題がないことも検証できましたので、当記事を修正しました。

ご指摘の程、誠にありがとうございました。
Androidの実装方法について
2重のforループでGetPixelを使用すると、サイズの大きい画像ではかなり長時間かかってしまうので、GetPixelsを使用した方が良いのではないでしょうか。

var pixels = new int[image.Width * image.Height];
image.GetPixels(pixels, 0, image.Width, 0, 0, image.Width, image.Height);
var rgbBytes = new List<byte>();
foreach (var argb in pixels)
{
var color = new Android.Graphics.Color(argb);
rgbBytes.Add(color.R);
rgbBytes.Add(color.G);
rgbBytes.Add(color.B);
}
return rgbBytes.ToArray();
コメントの投稿

※名前とタイトルが入力されていないコメントでは他のコメントとの区別ができません。

 入力されていないコメントには返信しませんのであらかじめご了承くださいませ。

※ニックネームでも良いので必ずご入力ください。

    

※必ずご入力ください。

    
    

※必ずご入力ください。

※技術的な質問には環境やエラーについて正確かつ詳細にお教えください。

・正確なエラーの内容

・Windowsのバージョン番号

・Visual Studioのバージョン

・機器の型番

・アプリやソフトのバージョン

    

カテゴリ別記事一覧

広告

プロフィール

石河 純


著者名 :石河 純
自己紹介:素人上がりのIT技術者。趣味は卓球・車・ボウリング

IT関連の知識はざっくりとこんな感じです。
【OS関連】
WindowsServer: 2012/2008R2/2003/2000/NT4
Windows: 10/8/7/XP/2000/me/NT4/98
Linux: CentOS RedHatLinux9
Mac: macOS Catalina 10.15 / Mojave 10.14 / High Sierra 10.13 / Sierra 10.12 / OSX Lion 10.7.5 / OSX Snow Leopard 10.6.8
【言語】
VB.net ASP.NET C#.net Java VBA
Xamarin.Forms
【データベース】
Oracle 10g/9i
SQLServer 2016/2008R2/2005/2000
SQLAnywhere 16/11/8
【BI/レポートツール】
Cognos ReportNet (IBM)
Microsoft PowerBI
ActiveReport (GrapeCity)
CrystalReport
【OCX関連】
GrapeCity InputMan SPREAD MultiRow GridView
【ネットワーク関連】
CCNP シスコ技術者認定
Cisco Catalyst シリーズ
Yamaha RTXシリーズ
FireWall関連
【WEB関連】
SEO SEM CSS jQuery IIS6/7 apache2

休みの日は卓球をやっています。
現在、卓球用品通販ショップは休業中です。