Unity 3D : RAW 10 bit 轉 RGB ( GPU 版 ) [ 新版本 2 ]

哈哈哈,寫了好多個版本了,這次又有新功能啦

這次可以支持四種拜爾排列方式:GRBG, GBRG, RGGB, BGGR

另外也能統計 R, G1, G2, B 通道的平均值

這裏寫圖片描述

C # :

using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using UnityEngine;
using UnityEngine.UI;

public class RAW_To_RGB : MonoBehaviour
{
    public RawImage outputTexture_RAW, outputTexture_RGB;
    public ComputeShader shader;

    void Start()
    {
        System.Diagnostics.Stopwatch time = new System.Diagnostics.Stopwatch();
        time.Start();

        // 圖片地址, RAW 格式(bit數&排列方式), 圖片寬, 圖片高
        ImageData imgData = Read_RAW_RGB("C:/FFMPEG/Hello.raw", "RAW10_GRBG", 4208, 3120);

        time.Stop();
        print("執行 " + time.Elapsed.TotalSeconds + " 秒");

        outputTexture_RAW.texture = imgData.TextureRAW;
        outputTexture_RGB.texture = imgData.TextureRGB;

        print("All : " + imgData.AvgColorAll + "    AvgG1 : " + imgData.AvgColor1
            + "    AvgR : " + imgData.AvgColor2 + "    AvgB : " + imgData.AvgColor3 + "    AvgG2 : " + imgData.AvgColor4);
    }

    // format : RAW10_RGGB, RAW10_BGGR, RAW10_GRBG, RAW10_GBRG
    // format example : RAW10_RGGB = RAW 10bit R:1, G:2, G:3, B:4
    public ImageData Read_RAW_RGB(string filePath, string format, int width, int height)
    {
        int ThreadGroupSize_X = 8; // 別亂動,動了統計資訊那邊會有 BUG,也許沒動也會有 ? 哈
        int ThreadGroupSize_Y = 8; // 別亂動,動了統計資訊那邊會有 BUG,也許沒動也會有 ? 哈

        int ThreadGroupSize = ThreadGroupSize_X * ThreadGroupSize_Y;

        RenderTexture texture_RAW = new RenderTexture(width, height, 24);
        texture_RAW.enableRandomWrite = true;
        texture_RAW.Create();

        RenderTexture texture_RGB = new RenderTexture(width, height, 24);
        texture_RGB.enableRandomWrite = true;
        texture_RGB.Create();

        int k = shader.FindKernel(format);
        shader.SetTexture(k, "outputTexture_RAW", texture_RAW);
        shader.SetTexture(k, "outputTexture_RGB", texture_RGB);
        shader.SetInt("width", width);
        shader.SetInt("height", height);

        // -----------------------------------------------------------------------------------
        // 將整個檔案放入 GPU

        int[] file = ByteArray_To_IntArray(File.ReadAllBytes(filePath));
        ComputeBuffer file_buffer = new ComputeBuffer(file.Length, sizeof(int));
        file_buffer.SetData(file);
        shader.SetBuffer(k, "file", file_buffer);

        // -----------------------------------------------------------------------------------
        // 初始化統計資料的參數

        uint[] SumColor1_Array = new uint[ThreadGroupSize];
        ComputeBuffer sumColor1_buffer = new ComputeBuffer(SumColor1_Array.Length, sizeof(uint));
        sumColor1_buffer.SetData(SumColor1_Array);
        shader.SetBuffer(k, "SumColor1_Array", sumColor1_buffer);

        uint[] SumColor2_Array = new uint[ThreadGroupSize];
        ComputeBuffer sumColor2_buffer = new ComputeBuffer(SumColor2_Array.Length, sizeof(uint));
        sumColor2_buffer.SetData(SumColor2_Array);
        shader.SetBuffer(k, "SumColor2_Array", sumColor2_buffer);

        uint[] SumColor3_Array = new uint[ThreadGroupSize];
        ComputeBuffer sumColor3_buffer = new ComputeBuffer(SumColor3_Array.Length, sizeof(uint));
        sumColor3_buffer.SetData(SumColor3_Array);
        shader.SetBuffer(k, "SumColor3_Array", sumColor3_buffer);

        uint[] SumColor4_Array = new uint[ThreadGroupSize];
        ComputeBuffer sumColor4_buffer = new ComputeBuffer(SumColor4_Array.Length, sizeof(uint));
        sumColor4_buffer.SetData(SumColor4_Array);
        shader.SetBuffer(k, "SumColor4_Array", sumColor4_buffer);

        // -----------------------------------------------------------------------------------
        // 執行

        shader.Dispatch(k, width / ThreadGroupSize_X, height / ThreadGroupSize_Y, 1);

        // -----------------------------------------------------------------------------------
        // 取得統計資料並計算

        sumColor1_buffer.GetData(SumColor1_Array);
        sumColor2_buffer.GetData(SumColor2_Array);
        sumColor3_buffer.GetData(SumColor3_Array);
        sumColor4_buffer.GetData(SumColor4_Array);

        long SumColor1 = 0, SumColor2 = 0, SumColor3 = 0, SumColor4 = 0;

        for (int i = 0; i < SumColor1_Array.Length; i++)
        {
            SumColor1 += SumColor1_Array[i];
            SumColor2 += SumColor2_Array[i];
            SumColor3 += SumColor3_Array[i];
            SumColor4 += SumColor4_Array[i];
        }

        ImageData imgData = new ImageData();
        imgData.Base = (width * height) / 4;
        imgData.AvgColorAll = ((SumColor1 + SumColor2 + SumColor3 + SumColor4) / 4) / imgData.Base;
        imgData.AvgColor1 = SumColor1 / imgData.Base;
        imgData.AvgColor2 = SumColor2 / imgData.Base;
        imgData.AvgColor3 = SumColor3 / imgData.Base;
        imgData.AvgColor4 = SumColor4 / imgData.Base;
        imgData.TextureRAW = texture_RAW;
        imgData.TextureRGB = texture_RGB;

        // -----------------------------------------------------------------------------------
        // 釋放資源

        file_buffer.Dispose();
        sumColor1_buffer.Dispose();
        sumColor2_buffer.Dispose();
        sumColor3_buffer.Dispose();
        sumColor4_buffer.Dispose();

        // -----------------------------------------------------------------------------------

        return imgData;
    }

    int[] ByteArray_To_IntArray(byte[] b)
    {
        int[] i = new int[b.Length];

        int thread_count = 8; // 設定線程數量

        // 如果設定的線程數量可以被整除,那就用多線程,否則用單線程。
        if (i.Length % thread_count != 0)
        {
            //單線程
            for (int x = 0; x < b.Length; x++)
            {
                i[x] = b[x];
            }
        }
        else
        {
            //多線程
            int thread_size = i.Length / thread_count;

            using (ManualResetEvent finish = new ManualResetEvent(false))
            {
                int currentThreadCount = thread_count;

                for (int t = 0; t < thread_count; t++)
                {
                    int start = thread_size * t;
                    int end = thread_size * t + thread_size;
                    int[] v = new int[] { start, end };

                    ThreadPool.QueueUserWorkItem((System.Object state) =>
                    {
                        int[] v2 = state as int[];
                        int start2 = v2[0];
                        int end2 = v2[1];

                        for (int x = start2; x < end2; x++)
                        {
                            i[x] = b[x];
                        }

                        if (Interlocked.Decrement(ref currentThreadCount) == 0)
                        {
                            finish.Set();
                        }
                    }, v);
                }
                // 等待所有 Thread 執行完畢
                finish.WaitOne();
            }
        }
        return i;
    }

    public struct ImageData
    {
        public Texture TextureRAW;
        public Texture TextureRGB;

        public float AvgColorAll;
        public float AvgColor1;
        public float AvgColor2;
        public float AvgColor3;
        public float AvgColor4;

        public float Base;
    }
}

ComputeShader :

#pragma kernel RAW10_RGGB
#pragma kernel RAW10_BGGR
#pragma kernel RAW10_GRBG
#pragma kernel RAW10_GBRG


int width, height; // 輸入圖像寬高

Buffer <int> file; // 輸入檔案 Byte 流

RWTexture2D<float4> outputTexture_RAW; // 輸出 RAW 貼圖

RWTexture2D<float4> outputTexture_RGB; // 輸出 RGB 貼圖

RWBuffer <uint> SumColor1_Array, SumColor2_Array, SumColor3_Array, SumColor4_Array;

[numthreads(8, 8, 1)]
void RAW10_RGGB(uint3 id : SV_DispatchThreadID, uint groupIndex : SV_GroupIndex)
{
    //------------------------------------------------------------------------------------------
    // 只讓左上角的點進入

    uint x = id.x, y = height - id.y - 1;

    if (x % 2 != 0 || y % 2 != 0) return;

    //------------------------------------------------------------------------------------------
    // 處理 RAW 檔

    int width_byte = width * 2;

    int i = ((width * y) + x) * 2; // 因為 RAW 10bit 佔用 2 個 byte 所以要乘二

    int R = file[i] | (file[i + 1] << 8);                               // 左上
    int G1 = file[i + 2] | (file[i + 3] << 8);                          // 右上
    int G2 = file[i + width_byte] | (file[i + 1 + width_byte] << 8);    // 左下
    int B = file[i + width_byte + 2] | (file[i + 3 + width_byte] << 8); // 右下

    float r = R / 1023.0f;
    float g1 = G1 / 1023.0f;
    float g2 = G2 / 1023.0f;
    float b = B / 1023.0f;

    outputTexture_RAW[uint2(id.x, id.y)] = float4(r, 0, 0, 1);         // 左上
    outputTexture_RAW[uint2(id.x + 1, id.y)] = float4(0, g1, 0, 1);    // 右上
    outputTexture_RAW[uint2(id.x, id.y - 1)] = float4(0, g2, 0, 1);    // 左下
    outputTexture_RAW[uint2(id.x + 1, id.y - 1)] = float4(0, 0, b, 1); // 右下

    //------------------------------------------------------------------------------------------
    // 處理 RGB 檔

    float4 Color = float4(r, (g1 + g2) / 2, b, 1);
    outputTexture_RGB[uint2(id.x, id.y)] = Color;         // 左上
    outputTexture_RGB[uint2(id.x + 1, id.y)] = Color;     // 右上
    outputTexture_RGB[uint2(id.x, id.y - 1)] = Color;     // 左下
    outputTexture_RGB[uint2(id.x + 1, id.y - 1)] = Color; // 右下

    //------------------------------------------------------------------------------------------
    // 統計資訊     

    InterlockedAdd(SumColor1_Array[groupIndex.x], R); // 左上
    InterlockedAdd(SumColor2_Array[groupIndex.x], G1);  // 右上
    InterlockedAdd(SumColor3_Array[groupIndex.x], G2);  // 左下
    InterlockedAdd(SumColor4_Array[groupIndex.x], B); // 右下
}

[numthreads(8, 8, 1)]
void RAW10_BGGR(uint3 id : SV_DispatchThreadID, uint groupIndex : SV_GroupIndex)
{
    //------------------------------------------------------------------------------------------
    // 只讓左上角的點進入

    uint x = id.x, y = height - id.y - 1;

    if (x % 2 != 0 || y % 2 != 0) return;

    //------------------------------------------------------------------------------------------
    // 處理 RAW 檔

    int width_byte = width * 2;

    int i = ((width * y) + x) * 2; // 因為 RAW 10bit 佔用 2 個 byte 所以要乘二

    int B = file[i] | (file[i + 1] << 8);                               // 左上
    int G1 = file[i + 2] | (file[i + 3] << 8);                          // 右上
    int G2 = file[i + width_byte] | (file[i + 1 + width_byte] << 8);    // 左下
    int R = file[i + width_byte + 2] | (file[i + 3 + width_byte] << 8); // 右下

    float b = R / 1023.0f;
    float g1 = G1 / 1023.0f;
    float g2 = G2 / 1023.0f;
    float r = B / 1023.0f;

    outputTexture_RAW[uint2(id.x, id.y)] = float4(0, 0, b, 1);         // 左上
    outputTexture_RAW[uint2(id.x + 1, id.y)] = float4(0, g1, 0, 1);    // 右上
    outputTexture_RAW[uint2(id.x, id.y - 1)] = float4(0, g2, 0, 1);    // 左下
    outputTexture_RAW[uint2(id.x + 1, id.y - 1)] = float4(r, 0, 0, 1); // 右下

    //------------------------------------------------------------------------------------------
    // 處理 RGB 檔

    float4 Color = float4(r, (g1 + g2) / 2, b, 1);
    outputTexture_RGB[uint2(id.x, id.y)] = Color;         // 左上
    outputTexture_RGB[uint2(id.x + 1, id.y)] = Color;     // 右上
    outputTexture_RGB[uint2(id.x, id.y - 1)] = Color;     // 左下
    outputTexture_RGB[uint2(id.x + 1, id.y - 1)] = Color; // 右下

    //------------------------------------------------------------------------------------------
    // 統計資訊

    InterlockedAdd(SumColor1_Array[groupIndex.x], B);  // 左上
    InterlockedAdd(SumColor2_Array[groupIndex.x], G1); // 右上
    InterlockedAdd(SumColor3_Array[groupIndex.x], G2); // 左下
    InterlockedAdd(SumColor4_Array[groupIndex.x], R);  // 右下
}

[numthreads(8, 8, 1)]
void RAW10_GRBG(uint3 id : SV_DispatchThreadID, uint groupIndex : SV_GroupIndex)
{
    //------------------------------------------------------------------------------------------
    // 只讓左上角的點進入

    uint x = id.x, y = height - id.y - 1;

    if (x % 2 != 0 || y % 2 != 0) return;

    //------------------------------------------------------------------------------------------
    // 處理 RAW 檔

    int width_byte = width * 2;

    int i = ((width * y) + x) * 2; // 因為 RAW 10bit 佔用 2 個 byte 所以要乘二

    int G1 = file[i] | (file[i + 1] << 8);                               // 左上
    int R = file[i + 2] | (file[i + 3] << 8);                            // 右上
    int B = file[i + width_byte] | (file[i + 1 + width_byte] << 8);      // 左下
    int G2 = file[i + width_byte + 2] | (file[i + 3 + width_byte] << 8); // 右下

    float g1 = G1 / 1023.0f;
    float r = R / 1023.0f;
    float b = B / 1023.0f;
    float g2 = G2 / 1023.0f;

    outputTexture_RAW[uint2(id.x, id.y)] = float4(0, g1, 0, 1);         // 左上
    outputTexture_RAW[uint2(id.x + 1, id.y)] = float4(r, 0, 0, 1);      // 右上
    outputTexture_RAW[uint2(id.x, id.y - 1)] = float4(0, 0, b, 1);      // 左下
    outputTexture_RAW[uint2(id.x + 1, id.y - 1)] = float4(0, g2, 0, 1); // 右下

    //------------------------------------------------------------------------------------------
    // 處理 RGB 檔

    float4 Color = float4(r, (g1 + g2) / 2, b, 1);
    outputTexture_RGB[uint2(id.x, id.y)] = Color;         // 左上
    outputTexture_RGB[uint2(id.x + 1, id.y)] = Color;     // 右上
    outputTexture_RGB[uint2(id.x, id.y - 1)] = Color;     // 左下
    outputTexture_RGB[uint2(id.x + 1, id.y - 1)] = Color; // 右下

    //------------------------------------------------------------------------------------------
    // 統計資訊

    InterlockedAdd(SumColor1_Array[groupIndex.x], G1);
    InterlockedAdd(SumColor2_Array[groupIndex.x], R);
    InterlockedAdd(SumColor3_Array[groupIndex.x], B);
    InterlockedAdd(SumColor4_Array[groupIndex.x], G2);
}

[numthreads(8, 8, 1)]
void RAW10_GBRG(uint3 id : SV_DispatchThreadID, uint groupIndex : SV_GroupIndex)
{
    //------------------------------------------------------------------------------------------
    // 只讓左上角的點進入

    uint x = id.x, y = height - id.y - 1;

    if (x % 2 != 0 || y % 2 != 0) return;

    //------------------------------------------------------------------------------------------
    // 處理 RAW 檔

    int width_byte = width * 2;

    int i = ((width * y) + x) * 2; // 因為 RAW 10bit 佔用 2 個 byte 所以要乘二

    int G1 = file[i] | (file[i + 1] << 8);                               // 左上
    int B = file[i + 2] | (file[i + 3] << 8);                            // 右上
    int R = file[i + width_byte] | (file[i + 1 + width_byte] << 8);      // 左下
    int G2 = file[i + width_byte + 2] | (file[i + 3 + width_byte] << 8); // 右下

    float g1 = G1 / 1023.0f;
    float b = R / 1023.0f;
    float r = B / 1023.0f;
    float g2 = G2 / 1023.0f;

    outputTexture_RAW[uint2(id.x, id.y)] = float4(0, g1, 0, 1);         // 左上
    outputTexture_RAW[uint2(id.x + 1, id.y)] = float4(0, 0, b, 1);      // 右上
    outputTexture_RAW[uint2(id.x, id.y - 1)] = float4(r, 0, 0, 1);      // 左下
    outputTexture_RAW[uint2(id.x + 1, id.y - 1)] = float4(0, g2, 0, 1); // 右下

    //------------------------------------------------------------------------------------------
    // 處理 RGB 檔

    float4 Color = float4(r, (g1 + g2) / 2, b, 1);
    outputTexture_RGB[uint2(id.x, id.y)] = Color;         // 左上
    outputTexture_RGB[uint2(id.x + 1, id.y)] = Color;     // 右上
    outputTexture_RGB[uint2(id.x, id.y - 1)] = Color;     // 左下
    outputTexture_RGB[uint2(id.x + 1, id.y - 1)] = Color; // 右下

    //------------------------------------------------------------------------------------------
    // 統計資訊     

    InterlockedAdd(SumColor1_Array[groupIndex.x], G1);
    InterlockedAdd(SumColor2_Array[groupIndex.x], B);
    InterlockedAdd(SumColor3_Array[groupIndex.x], R);
    InterlockedAdd(SumColor4_Array[groupIndex.x], G2);
}
發佈了75 篇原創文章 · 獲贊 18 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章