I have black Raw Bayer Images RGGB color space. I want to go over each pixel in their channel and sum them up for each channel, then divide it by the number of pixels for each channel. I'm trying to build a fast optimized algorithm.
Here is how I have started. The code runs but I still have some issues with the results. Please comment about optimizing my code and if there a better way to calculate the black level of an image.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BlackLevelCorrectionParallel
{
class Program
{
static void Main(string[] args)
{
string directoryPath = @"C:\Examples\blc\";
uint width = 1800;
uint height = 1200;
uint bpp = 10;
uint colorSpace = 0; //RGGB
List<BlcResults> results = new List<BlcResults>();
Parallel.ForEach(Directory.GetFiles(directoryPath, "*.raw").Select(Path.GetFullPath), rawImagePath =>
{
Image newImage = new Image(width, height, bpp, colorSpace);
newImage.ReadImage(rawImagePath);
BlcResults res = newImage.CalculateBlackLevel();
results.Add(res);
});
}
}
}
Here is my image class - it basically has two functions - readImage and Algorithm.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BlackLevelCorrectionParallel
{
public class Image
{
public uint Width { get; set; }
public uint Height { get; set; }
public uint BPP { get; set; }
public uint ColorSpace { get; set; }
public byte[] Data { get; set; }
public Image(uint width, uint height, uint bPP, uint colorSpace)
{
BPP = bPP;
ColorSpace = colorSpace;
Height = height;
Width = width;
}
public void ReadImage(string path)
{
byte[] fileData = null;
if (!File.Exists(path))
{
throw new FileNotFoundException(path);
}
fileData = File.ReadAllBytes(path);
var bytesPerPixel = (BPP + 7) / 8;
var dataSize = Width * Height * bytesPerPixel;
Data = new byte[Width * Height * bytesPerPixel];
var sdata = new short[dataSize / 2];
for (int i = 0, shortIndex = 0; i < dataSize; i += 2, shortIndex++)
{
CopyBytesToShort(fileData[i], fileData[i + 1], out sdata[shortIndex], (int)BPP, false);
}
Buffer.BlockCopy(sdata, 0, Data, 0, Data.Length);
}
private void CopyBytesToShort(byte byte1, byte byte2, out short retShort, int bitsPerPixel, bool isPerformShift)
{
short lsb, msb;
lsb = byte1;
msb = byte2;
if (isPerformShift)
{
lsb <<= 16 - bitsPerPixel;
msb <<= (16 - (bitsPerPixel - 8));
}
else
{
msb <<= 8;
}
retShort = (short)(msb | lsb);
}
public BlcResults CalculateBlackLevel()
{
double channelGR = 0;
double channelR = 0;
double channelGB = 0;
double channelB = 0;
if (ColorSpace == 0) //RGGB
{
for (int i = 0; i < Width; i++)
{
for (int j = 0; j < Height; j++)
{
if (i % 2 == 0 && j % 2 == 0)
{
channelR += Data[i * Height + j];
}
else if (i % 2 == 0 && j % 2 == 1)
{
channelGR += Data[i * Height + j];
}
else if (i % 2 == 1 && j % 2 == 0)
{
channelGB += Data[i * Height + j];
}
else if (i % 2 == 1 && j % 2 == 1)
{
channelB += Data[i * Height + j];
}
}
}
}
else if (ColorSpace == 1)
{
}
else if (ColorSpace == 2)
{
}
else if (ColorSpace == 3)
{
}
double avgChannelB = channelB / ((Width / 2) * (Height / 2));
double avgChannelGB = channelGB / ((Width / 2) * (Height / 2));
double avgChannelGR = channelGR / ((Width / 2) * (Height / 2));
double avgChannelR = channelR / ((Width / 2) * (Height / 2));
BlcResults results = new BlcResults(channelB, channelGB, channelGR, channelR);
return results;
}
}
}
Helper class for results
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BlackLevelCorrectionParallel
{
public class BlcResults
{
double AvgChannelB { get; set; }
double AvgChannelGb { get; set; }
double AvgChannelGr { get; set; }
double AvgChannelR { get; set; }
public BlcResults(double channelB, double channelGb, double channelGr, double channelR)
{
AvgChannelB = channelB;
AvgChannelGb = channelGb;
AvgChannelGr = channelGr;
AvgChannelR = channelR;
}
}
}