I'm doing filtering on a depth image and I would like to convert that piece of code into job system of unity, because it's so slow. The image update is called each frame
public unsafe void DRSFilter( byte * src, byte * dst, uint data_delta, uint history_scan_depth)
{
if (history_scan_depth > history_capacity)
{
history_scan_depth = history_capacity;
}
for (int i = 0; i < layer_size; i++)
{
byte b = src[i];
bool is_color_pixel = false;
uint avrg = 0;
for (int k = 0; k < history_scan_depth; k++)
{
avrg += history[k * layer_size + i];
if (history[k * layer_size + i] > 0)
{
is_color_pixel = true;
// break;
}
}
average[i] = (byte)(avrg / history_scan_depth);
//if (b > 0 || b == 0 && !is_color_pixel) {
if (Abs(b - average[i]) < data_delta)
{
dst[i] = b;
}
// }
history[layer * layer_size + i] = b;
}
layer++;
if (layer == history_scan_depth)
{
layer = 0;
}
}
private unsafe void ImageUpdated(Camera cam, ref Mat cvMatDepth)
{
long addrsrc = cvMatDepth.dataAddr();
long addrDst = dstResult.dataAddr();
DRSFilter((byte*)addrsrc, (byte*)addrDst, a, b);
Utils.matToTexture2D(dstResult, texture);
canvas.GetComponent<RawImage>().texture = texture;
}
Update Sketch:
[BurstCompile] // <-- For this you need to add the Burst package using the Unity package manager, this attribute is completely optional but it improves performance by a lot (like 10 times faster)
public struct ConvertJobParallel : IJobParallelFor
{
public NativeArray<byte> input;
public NativeArray<byte> output;
public NativeArray<byte> history;
public NativeArray<byte> average;
public int _history_scan_depth;
public int _history_capacity;
public int _layer_size;
public int _data_delta;
public int _layer;
// This gets called by the job system. index ranges between 0 and the 'arrayLength' specified in the first parameter of Schedule()
public void Execute(int index)
{
if (_history_scan_depth > _history_capacity)
{
_history_scan_depth = _history_capacity;
}
byte b = input[index];
uint avrg = 0;
for (int k = 0; k < _history_scan_depth; k++)
{
avrg += history[k * _layer_size + index];
}
average[index] = (byte)(avrg / _history_scan_depth);
if (Math.Abs(b - average[index]) < _data_delta)
{
output[index] = b;
}
history[_layer * _layer_size + index] = b;
_layer++;
if (_layer == _history_scan_depth)
{
_layer = 0;
}
}
}
[SerializeField] private Texture2D _inputTexture; // Texture that we are reading, should have read/write enabled set to true and Compression set to None
[SerializeField] private Texture2D rawImage;
private Texture2D _outputTexture;
private NativeArray<byte> inputArray;
private NativeArray<byte> outputArray;
private NativeArray<byte> historyArray;
private NativeArray<byte> averageArray;
private int _history_scan_depth;
private int _history_capacity;
private int _data_delta;
private int _layer;
private void Awake()
{
historyArray = new NativeArray<byte>(history_capacity * layer_size, Allocator.Persistent);
averageArray = new NativeArray<byte>(layer_size, Allocator.Persistent);
outputArray = new NativeArray<byte>(layer_size, Allocator.Persistent);
}
private void OnDestroy()
{
historyArray.Dispose(); // We need to manually dispose our NativeArrays. The arrays retrieved from the Textures are disposed by the textures so we don't care here
averageArray.Dispose();
outputArray.Dispose();
}
private void ImageUpdated(ref Texture2D zedTextureDepth)
{
inputArray = zedTextureDepth.GetRawTextureData<byte>(); // Could use GetPixelData instead when working with mipmaps
var job = new ConvertJobParallel()
{
input = inputArray,
output = outputArray,
history = historyArray,
average = averageArray,
_history_scan_depth = history_scan_depth,
_history_capacity = history_capacity,
_layer_size = layer_size,
_data_delta = data_delta,
_layer = layer
};
JobHandle handle1 = job.Schedule(inputArray.Length, 100); // The 100 here is a magic number, it is basically a number that says how many items (Color32 in our example) are handled in one 'batch' where each batch can run async on any thread
JobHandle.ScheduleBatchedJobs(); // Start running (all) our previously scheduled jobs
handle1.Complete(); // Wait on the main thread fot this job to complete
_outputTexture.LoadRawTextureData(outputArray);
_outputTexture.Apply(); // Copy changes to gpu
canvas.GetComponent<RawImage>().texture = rawImage;
}
src(call this one_MainTexfor blitting convenience). In the fragment shader, sample the corresponding texel from each history page to compute the average, and use that to determine your output value. Use Graphics.Blit to run this shader on thesrctexture, outputting its results into a RenderTexture of the same dimensions. Then replace one of the history pages with the new data. \$\endgroup\$