哈哈哈,寫了好多個版本了,這次又有新功能啦
這次可以支持四種拜爾排列方式: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);
}