К сожалению, после применения преобразований для протанопии и дейтеранопии Полученные изображения показывают черные дыры. Изображение выглядит почти черным с некоторыми странными искажениями, напоминающими «дыры». Я подозреваю, что что-то не так с преобразованиями или масштабированием каналов RGB, но не могу точно определить причину.
Описание проблемы:
Я использую C# для обработки изображений и файлового ввода-вывода.
Я написал ассемблерный код (ASM) для имитации преобразований дальтонизма.
После запуска моделирования обработанное изображение почти полностью черное с странные «дырчатые» области.
Что я пробовал:
- Дважды проверил преобразования для каждой тип дальтонизма (дейтеранопия, протанопия).
- Убедился, что значения RGB правильно рассчитаны и зафиксированы в диапазоне 0–255.
- Проверено, что изображение загружается и сохраняется правильно в C#.
private void ProcessColorBlindnessAsm(int blindnessType)
{
if (_originalImage == null || _processedImage == null)
{
MessageBox.Show("Błąd: Image not loaded.");
return;
}
Rectangle rect = new Rectangle(0, 0, _originalImage.Width, _originalImage.Height);
BitmapData originalData = _originalImage.LockBits(rect, ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
BitmapData processedData = _processedImage.LockBits(rect, ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
int pixelCount = _originalImage.Width * _originalImage.Height;
int stride = originalData.Stride;
IntPtr originalPtr = originalData.Scan0;
IntPtr processedPtr = processedData.Scan0;
try
{
Parallel.For(0, Environment.ProcessorCount, partition =>
{
int rowsPerPartition = _originalImage.Height / Environment.ProcessorCount;
int startRow = partition * rowsPerPartition;
int endRow = (partition == Environment.ProcessorCount - 1) ? _originalImage.Height : startRow + rowsPerPartition;
int partitionPixelCount = (endRow - startRow) * _originalImage.Width;
IntPtr originalPartitionPtr = IntPtr.Add(originalPtr, startRow * stride);
IntPtr processedPartitionPtr = IntPtr.Add(processedPtr, startRow * stride);
// Pass blindnessType to the ASM function
DeuteranopiaAsm(originalPartitionPtr, processedPartitionPtr, partitionPixelCount, stride, blindnessType);
});
}
catch (Exception ex)
{
MessageBox.Show($"Error while processing asm: {ex.Message}");
}
finally
{
_originalImage.UnlockBits(originalData);
_processedImage.UnlockBits(processedData);
}
}
< /code>
ASM Code: < /p>
.code
DeuteranopiaAsm proc
SimulateColorBlindnessASM:
; RCX = originalImage (pointer)
; RDX = processedImage (pointer)
; R8 = pixelCount (number of pixels)
; R9 = stride (bytes per row)
; R10 = blindnessType (0 = Deuteranopia, 1 = Protanopia, 2 = Tritanopia)
mov r11, rcx ; Save pointer to original image
mov r12, rdx ; Save pointer to processed image
xor rbx, rbx ; Use RBX as pixel counter
PixelLoop:
cmp rbx, r8 ; Check if all pixels are processed
jge EndLoop ; If rbx >= pixelCount, exit
mov rax, rbx ; Copy pixel counter to rax
shl rax, 1 ; rax = rbx * 2 (shift left by 1)
add rax, rbx ; rax = rax + rbx = rbx * 3
; Load color data (B, G, R)
mov al, byte ptr [r11 + rax] ; Load blue channel
mov cl, byte ptr [r11 + rax + 1] ; Load green channel
mov dl, byte ptr [r11 + rax + 2] ; Load red channel
; Select transformation based on blindnessType
cmp r10, 0 ; Check if Deuteranopia
je SimulateDeuteranopia
cmp r10, 1 ; Check if Protanopia
je SimulateProtanopia
cmp r10, 2 ; Check if Tritanopia
je SimulateTritanopia
jmp EndPixel ; Skip if invalid type
SimulateDeuteranopia:
; Transform for Deuteranopia
movzx r8d, dl ; Convert red channel to 32-bit
imul r8d, 625 ; R = R * 0.625
movzx r9d, cl ; Convert green channel to 32-bit
imul r9d, 375 ; G = G * 0.375
add r8d, r9d ; New Red = (R * 0.625 + G * 0.375)
shr r8d, 8 ; Divide by 256 to fit in byte range
; Green transformation (G = G * 0.7)
movzx r9d, cl ; Convert green channel to 32-bit
imul r9d, 700 ; G = G * 0.7
shr r9d, 10 ; Divide by 1024 to fit in byte range
; Blue transformation (B = B * 0.8)
movzx r10d, al ; Convert blue channel to 32-bit
imul r10d, 800 ; B = B * 0.8
shr r10d, 10 ; Divide by 1024 to fit in byte range
; Store processed pixel back into the image
mov byte ptr [r12 + rax], al ; Store blue channel
mov byte ptr [r12 + rax + 1], cl ; Store green channel
mov byte ptr [r12 + rax + 2], dl ; Store red channel
jmp EndPixel
SimulateProtanopia:
; Transform for Protanopia
movzx r8d, dl ; Convert red channel to 32-bit
imul r8d, 567 ; R = R * 0.567
movzx r9d, cl ; Convert green channel to 32-bit
imul r9d, 433 ; G = G * 0.433
add r8d, r9d ; New Red = (R * 0.567 + G * 0.433)
shr r8d, 8 ; Divide by 256
; Green transformation (G = G * 0.558)
movzx r9d, cl ; Convert green channel to 32-bit
imul r9d, 558 ; G = G * 0.558
shr r9d, 10 ; Divide by 1024 to fit in byte range
; Blue transformation (B = B * 0.0)
xor r10d, r10d ; Set blue channel to 0
; Store processed pixel back into the image
mov byte ptr [r12 + rax], al ; Store blue channel
mov byte ptr [r12 + rax + 1], cl ; Store green channel
mov byte ptr [r12 + rax + 2], dl ; Store red channel
jmp EndPixel
SimulateTritanopia:
; Transform for Tritanopia
movzx r8d, dl ; Convert red channel to 32-bit
imul r8d, 950 ; R = R * 0.95
movzx r9d, cl ; Convert green channel to 32-bit
imul r9d, 433 ; G = G * 0.433
add r8d, r9d ; New Red = (R * 0.95 + G * 0.433)
shr r8d, 8 ; Divide by 256
movzx r9d, cl ; Convert green channel to 32-bit
imul r9d, 433 ; G = G * 0.433
shr r9d, 10 ; Divide by 1024 to fit in byte range
; Blue transformation (B = B * 0.567)
movzx r10d, al ; Convert blue channel to 32-bit
imul r10d, 567 ; B = B * 0.567
shr r10d, 10 ; Divide by 1024 to fit in byte range
; Store processed pixel back into the image
mov byte ptr [r12 + rax], al ; Store blue channel
mov byte ptr [r12 + rax + 1], cl ; Store green channel
mov byte ptr [r12 + rax + 2], dl ; Store red channel
jmp EndPixel
EndPixel:
; Store processed pixel back into the image
mov byte ptr [r12 + rax], al ; Store blue channel
mov byte ptr [r12 + rax + 1], cl ; Store green channel
mov byte ptr [r12 + rax + 2], dl ; Store red channel
inc rbx ; Increment pixel counter
jmp PixelLoop ; Repeat for next pixel
EndLoop:
ret
DeuteranopiaAsm endp
end
< /code>
Можете ли вы мне помочь? = "https://i.sstatic.net/jtp9wmkf.png"/>
Как это должно выглядеть:
my asm output:
Подробнее здесь: https://stackoverflow.com/questions/792 ... ulation-in