• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Ładowanie obrazu w assemblerze

Aruba Cloud - Virtual Private Server VPS
0 głosów
89 wizyt
pytanie zadane 5 stycznia w Assembler przez Machu03 Nowicjusz (140 p.)

Witam, mam problem związany z assemblerem. Na studiach uczę się assemblera, ale stanąłem pod ściana. dostałem zadanie, które polega na wczytaniu obrazu przy pomocy assemblera i c++. Chciałem wczytać obraz za pomocą c++, następnie przekazać parametry obrazu do assemblera i następnie znowu pokazać wczytany obraz bo przejściu przez assemblera. Mam problem z kodem, nie potrafię wczytać odpowiednio pikseli, jest to może problem z przekazywaniem obrazu bądź też z samym kodem assemblera. Obraz który zwraca mi program odpaleniu go jest "pusty".
Mam trzy pliki:
c++
masm
dll (tylko do przekazania metod)
Za każdą pomoc dziękuje :)

 

#include <opencv2/opencv.hpp>
#include <iostream>

extern "C" int _fastcall processImage(const unsigned char* inputBuffer, int width, int height, int channels, unsigned char* outputBuffer, int stride);

int main() {
    const char* imagePath = "C:/obraz.jpg";
    cv::Mat image = cv::imread(imagePath, cv::IMREAD_COLOR);

    if (image.empty()) {
        std::cerr << "Error: Could not load the image!" << std::endl;
        return -1;
    }

    cv::Mat outputImage(image.size(), image.type());

    if (!outputImage.data) {
        std::cerr << "Error: Could not allocate memory for output buffer!" << std::endl;
        return -1;
    }

    int stride = image.cols * image.channels();

    int result = processImage(
        image.data,                // Input buffer
        image.cols,                // Image width
        image.rows,                // Image height
        image.channels(),          // Number of channels (e.g., 3 for RGB)
        outputImage.data,          // Output buffer
        stride                     // Stride (width * channels)
    );

    if (result != 0) {
        std::cerr << "Error: Assembly function failed!" << std::endl;
        return -1;
    }

    cv::imshow("Output Image", outputImage);
    cv::waitKey(0);

    return 0;
}
;.586
;.MODEL FLAT, C

.DATA

.CODE

; Set up to load image data and apply a filter (convolution)
; rcx - input image pointer (pixels)
; rdx - output image pointer (pixels)
; r8 - filter pointer (kernel)
; r9 - current byte index (pixel index)
; rsp+40 - stride (width of the image in bytes)

; Purpose of registers:
; r10 - used for iterating through the kernel convolution
; r11 - number of bytes left to process

processImage proc export
    ; Load the amount of bytes to process
    MOV R11, [RSP+40]   ; Amount of bytes left to process
    SUB R11, 8           ; Adjust the byte count (account for stride)

NextPixel:
    MOV R10, R9          ; Set R10 to the current pixel index (center)
    SUB R10, [RSP+40]    ; Adjust to the top middle pixel
    SUB R10, 4           ; Adjust to top-left pixel

    ; Load 3x3 matrix of color-coded pixels into xmm registers
    PMOVZXBD xmm0, [RCX+R10]        ; Top-left
    PMOVZXBD xmm1, [RCX+R10+4]      ; Top-middle
    PMOVZXBD xmm2, [RCX+R10+8]      ; Top-right
    ADD R10, [RSP+40]               ; Move to the next line (stride)
    PMOVZXBD xmm3, [RCX+R10]        ; Middle-left
    PMOVZXBD xmm4, [RCX+R10+4]      ; Middle
    PMOVZXBD xmm5, [RCX+R10+8]      ; Middle-right
    ADD R10, [RSP+40]               ; Move to the next line (stride)
    PMOVZXBD xmm6, [RCX+R10]        ; Bottom-left
    PMOVZXBD xmm7, [RCX+R10+4]      ; Bottom-middle
    PMOVZXBD xmm8, [RCX+R10+8]      ; Bottom-right

    ; Apply the filter (multiply each pixel by the filter value)
    PMOVSXBD xmm9, [R8]             ; Load filter value
    VPBROADCASTD xmm9, xmm9        ; Broadcast filter value to all positions
    PMULLD xmm0, xmm9              ; Multiply top-left pixel by filter
    PMOVSXBD xmm9, [R8+4]           ; Load next filter value
    VPBROADCASTD xmm9, xmm9        ; Broadcast filter value
    PMULLD xmm1, xmm9              ; Multiply top-middle pixel by filter
    PMOVSXBD xmm9, [R8+8]           ; Load next filter value
    VPBROADCASTD xmm9, xmm9        ; Broadcast filter value
    PMULLD xmm2, xmm9              ; Multiply top-right pixel by filter

    ; Repeat for other pixels in the filter (left to right, top to bottom)
    PMOVSXBD xmm9, [R8+12]
    VPBROADCASTD xmm9, xmm9
    PMULLD xmm3, xmm9
    PMOVSXBD xmm9, [R8+16]
    VPBROADCASTD xmm9, xmm9
    PMULLD xmm4, xmm9
    PMOVSXBD xmm9, [R8+20]
    VPBROADCASTD xmm9, xmm9
    PMULLD xmm5, xmm9
    PMOVSXBD xmm9, [R8+24]
    VPBROADCASTD xmm9, xmm9
    PMULLD xmm6, xmm9
    PMOVSXBD xmm9, [R8+28]
    VPBROADCASTD xmm9, xmm9
    PMULLD xmm7, xmm9
    PMOVSXBD xmm9, [R8+32]
    VPBROADCASTD xmm9, xmm9
    PMULLD xmm8, xmm9

    ; Sum the components of the pixels (add the results of the multiplications)
    PADDD xmm0, xmm1
    PADDD xmm0, xmm2
    PADDD xmm0, xmm3
    PADDD xmm0, xmm4
    PADDD xmm0, xmm5
    PADDD xmm0, xmm6
    PADDD xmm0, xmm7
    PADDD xmm0, xmm8

    ; Check if the pixel value is between 0 and 255 (clamp to this range)
Blue:
    MOVD EAX, xmm0
    CMP EAX, 255
    JG BlueGreater
    CMP EAX, 0
    JL BlueLesser

Green:
    MOV [RDX+R9], AL            ; Store the result (Blue component)
    PSRLDQ xmm0, 4              ; Shift the next component (Green)
    MOVD EAX, xmm0
    CMP EAX, 255
    JG GreenGreater
    CMP EAX, 0
    JL GreenLesser

Red:
    MOV [RDX+R9+1], AL          ; Store the result (Green component)
    PSRLDQ xmm0, 4              ; Shift the next component (Red)
    MOVD EAX, xmm0
    CMP EAX, 255
    JG RedGreater
    CMP EAX, 0
    JL RedLesser

Alpha:
    MOV [RDX+R9+2], AL          ; Store the result (Red component)
    MOV EAX, 255
    MOV [RDX+R9+3], AL          ; Set the Alpha component to 255
    ADD R9, 4
    SUB R11, 4
    CMP R11, 0                  ; Check if there are more bytes to process
    JNE NextPixel
    ret

BlueGreater:
    MOV AL, 255                 ; Set Blue to 255 if it's greater
    JMP Green

BlueLesser:
    MOV AL, 0                   ; Set Blue to 0 if it's less
    JMP Green

GreenGreater:
    MOV AL, 255                 ; Set Green to 255 if it's greater
    JMP Red

GreenLesser:
    MOV AL, 0                   ; Set Green to 0 if it's less
    JMP Red

RedGreater:
    MOV AL, 255                 ; Set Red to 255 if it's greater
    JMP Alpha

RedLesser:
    MOV AL, 0                   ; Set Red to 0 if it's less
    JMP Alpha

processImage endp

END

.  

komentarz 5 stycznia przez adrian17 Mentor (352,580 p.)
Może czegoś tu nie rozumiem, ale zupełnie nie widzę jak argumenty funkcji w C++ie się mapują na argumenty w asm. W C++ie nie widzę gdziekolwiek filtra do konwolucji, a po stronie asma widzę że masz pętlę która się kończy jak przejedziesz całą szerokość ekranu, ale... to robi tylko jedną linię? Bo nigdzie nie widzę żebyś gdziekolwiek miał wysokość obrazu tam?

Próbowałeś to odpalać w zwykłym debuggerze i sprawdzić jakie są wartości rejestrów na samym początku funkcji w asmie? Bo pewnie są zupełnie inne niż się spodziewasz.

BTW, jak kompilujesz na x86-64, to _fastcall nic nie robi, nie?
komentarz 6 stycznia przez Machu03 Nowicjusz (140 p.)

@adrian17 ,  Dzięki za odpowiedź. Od wczoraj, kiedy wysłałeś swoją wiadomość, starałem się wprowadzić Twoje sugestie, ale nie jestem pewien, jak zrobić to poprawnie. Nie ukrywam, że zapytałem ChatGPT o wyjaśnienie koncepcji filtra do konwolucji, ponieważ nigdy o tym nie słyszałem na studiach. Na podstawie przykładu od prowadzących starałem się poprawnie przekazać te parametry z C++, ale jeśli dalej coś jest nie tak, to już nie wiem, jak to zrobić poprawnie.

Odnośnie debuggera i wartości rejestrów, o których wspomniałeś – udało mi się je znaleźć, ale w takim przypadku nie jestem pewien, co dokładnie powinienem z nimi zrobić.

Jeśli chodzi o Twoje pytanie o _fastcall, to nie zauważyłem, żeby to miało jakieś znaczenie.

Starałem się przerobić ten kod, aby działał poprawnie. Niestety nie udało mi się, ponieważ kod w tej chwili się nie kończy, i nie wiem dlaczego. Poniżej wstawiam, jak próbowałem to zmienić, ale stanąłem w martwym punkcie.

 

#include <iostream>
#include <vector>
#include <cstdint>
#include <opencv2/opencv.hpp>

// Deklaracja funkcji assemblerowej
extern "C" void processImage(
    uint8_t * inputImage,     
    uint8_t * outputImage,  
    int32_t * filter,         
    int imageWidth, 
    int imageHeight 
);

void applyFilter(
    const std::vector<uint8_t>& inputImage,
    std::vector<uint8_t>& outputImage,
    const std::vector<int32_t>& filter,
    int imageWidth,
    int imageHeight
) {
    if (inputImage.size() != outputImage.size()) {
        std::cerr << "Error: Input and output images must have the same size!" << std::endl;
        return;
    }
    if (filter.size() != 9) {
        std::cerr << "Error: Filter must be a 3x3 matrix!" << std::endl;
        return;
    }

processImage(const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(inputImage.data())), 
             outputImage.data(), 
             const_cast<int32_t*>(filter.data()), 
             imageWidth, 
             imageHeight);

}

int main() {
    std::string imagePath = "C:/Users/machm/OneDrive - Politechnika Śląska/Documents/sem5/APL/input zdjecia/spognebob.jpeg"; //"C:\Users\machm\OneDrive - Politechnika Śląska\Documents\sem5\APL\input zdjecia\spognebob.jpeg"
    cv::Mat inputMat = cv::imread(imagePath, cv::IMREAD_UNCHANGED);

    if (inputMat.empty()) {
        std::cerr << "Error: Could not load image from " << imagePath << std::endl;
        return -1;
    }

    if (inputMat.channels() != 4) {
        cv::cvtColor(inputMat, inputMat, cv::COLOR_BGR2BGRA);
    }

    int imageWidth = inputMat.cols;
    int imageHeight = inputMat.rows;

    std::vector<uint8_t> inputImage(inputMat.data, inputMat.data + inputMat.total() * inputMat.elemSize());
    std::vector<uint8_t> outputImage(inputImage.size(), 0);

    std::vector<int32_t> filter = {
        1, 1, 1,
        1, -8, 1,
        1, 1, 1
    };

    // Apply the filter
    applyFilter(inputImage, outputImage, filter, imageWidth, imageHeight);

    cv::Mat outputMat(imageHeight, imageWidth, CV_8UC4, outputImage.data());

    cv::imshow("Input Image", inputMat);
    cv::imshow("Processed Image", outputMat);
    cv::waitKey(0);

    return 0;
}
;.586
;.MODEL FLAT, C

.DATA

.CODE

processImage proc export
    ; Set up the height and total number of pixels
    MOV R12, [RSP+48]          ; Load image height
    IMUL R12, [RSP+40]         ; Height * width (total number of bytes/pixels)

NextRow:
    ; Processing one row
    MOV R11, [RSP+40]          ; Load the number of bytes in one row (stride)
    CALL NextPixel              

    SUB R12, [RSP+40]          ; Subtract one row from total pixels
    CMP R12, 0                  
    JLE FinishProcessing        

    JMP NextRow

NextPixel:
    MOV R10, R9                ; Set R10 to the current pixel index (center)
    SUB R10, [RSP+40]           ; Adjust for the current row (stride)
    SUB R10, 4                 

    ; Ensure we are within the bounds of the image
    CMP R10, 0                 ; Check if R10 (current pixel offset) is less than 0
    JL SkipPixel               
    CMP R10, [RSP+48]          ; Check if R10 is beyond image width
    JG SkipPixel               

    ; Load 3x3 matrix of color-coded pixels into xmm registers
    PMOVZXBD xmm0, [RCX+R10]        ; Top-left
    PMOVZXBD xmm1, [RCX+R10+4]      ; Top-middle
    PMOVZXBD xmm2, [RCX+R10+8]      ; Top-right
    ADD R10, [RSP+40]               ; Move to the next line (stride)
    PMOVZXBD xmm3, [RCX+R10]        ; Middle-left
    PMOVZXBD xmm4, [RCX+R10+4]      ; Middle
    PMOVZXBD xmm5, [RCX+R10+8]      ; Middle-right
    ADD R10, [RSP+40]               ; Move to the next line (stride)
    PMOVZXBD xmm6, [RCX+R10]        ; Bottom-left
    PMOVZXBD xmm7, [RCX+R10+4]      ; Bottom-middle
    PMOVZXBD xmm8, [RCX+R10+8]      ; Bottom-right

    ; Apply the filter (multiply each pixel by the filter value)
    PMOVSXBD xmm9, [R8]             ; Load filter value
    VPBROADCASTD xmm9, xmm9         
    PMULLD xmm0, xmm9                ; Multiply top-left pixel by filter
    PMOVSXBD xmm9, [R8+4]           ; Load next filter value
    VPBROADCASTD xmm9, xmm9         
    PMULLD xmm1, xmm9                ; Multiply top-middle pixel by filter
    PMOVSXBD xmm9, [R8+8]           
    VPBROADCASTD xmm9, xmm9        
    PMULLD xmm2, xmm9                ; Multiply top-right pixel by filter
    PMOVSXBD xmm9, [R8+12]
    VPBROADCASTD xmm9, xmm9
    PMULLD xmm3, xmm9               ; Multiply middle-left pixel by filter
    PMOVSXBD xmm9, [R8+16]
    VPBROADCASTD xmm9, xmm9
    PMULLD xmm4, xmm9               ; Multiply middle pixel by filter
    PMOVSXBD xmm9, [R8+20]
    VPBROADCASTD xmm9, xmm9
    PMULLD xmm5, xmm9               ; Multiply middle-right pixel by filter
    PMOVSXBD xmm9, [R8+24]
    VPBROADCASTD xmm9, xmm9
    PMULLD xmm6, xmm9               ; Multiply bottom-left pixel by filter
    PMOVSXBD xmm9, [R8+28]
    VPBROADCASTD xmm9, xmm9
    PMULLD xmm7, xmm9               ; Multiply bottom-middle pixel by filter
    PMOVSXBD xmm9, [R8+32]
    VPBROADCASTD xmm9, xmm9
    PMULLD xmm8, xmm9               ; Multiply bottom-right pixel by filter

    PADDD xmm0, xmm1                ; Add the results
    PADDD xmm0, xmm2
    PADDD xmm0, xmm3
    PADDD xmm0, xmm4
    PADDD xmm0, xmm5
    PADDD xmm0, xmm6
    PADDD xmm0, xmm7
    PADDD xmm0, xmm8

    ; Store the color components (Blue, Green, Red, Alpha)
    MOVD EAX, xmm0
    MOV [RDX+R9], AL            ; Store Blue component
    PSRLDQ xmm0, 4              ; Shift the next component (Green)
    MOVD EAX, xmm0
    MOV [RDX+R9+1], AL          ; Store Green component
    PSRLDQ xmm0, 4              ; Shift the next component (Red)
    MOVD EAX, xmm0
    MOV [RDX+R9+2], AL          ; Store Red component
    MOV EAX, 255
    MOV [RDX+R9+3], AL          ; Set the Alpha component to 255

    ADD R9, 4
    SUB R11, 4
    CMP R11, 0                  ; Check if there are more pixels in the row
    JNE NextPixel

    ret

SkipPixel:
    ; Skip processing the pixel if it's out of bounds
    ADD R10, 4
    SUB R11, 4
    CMP R11, 0
    JNE NextPixel
    ret

FinishProcessing:
    ; End of the processing
    ret

processImage endp

END

 

Zaloguj lub zarejestruj się, aby odpowiedzieć na to pytanie.

Podobne pytania

0 głosów
1 odpowiedź 228 wizyt
pytanie zadane 27 stycznia 2021 w Assembler przez MaTiDxxx Początkujący (290 p.)
0 głosów
1 odpowiedź 604 wizyt
pytanie zadane 1 grudnia 2020 w Assembler przez Tomek Gawlina Nowicjusz (150 p.)
0 głosów
0 odpowiedzi 1,125 wizyt
pytanie zadane 11 grudnia 2016 w Assembler przez Jędrzej Dembowski Użytkownik (740 p.)

93,327 zapytań

142,323 odpowiedzi

322,396 komentarzy

62,657 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj

Wprowadzenie do ITsec, tom 1 Wprowadzenie do ITsec, tom 2

Można już zamawiać dwa tomy książek o ITsec pt. "Wprowadzenie do bezpieczeństwa IT" - mamy dla Was kod: pasja (użyjcie go w koszyku), dzięki któremu uzyskamy aż 15% zniżki! Dziękujemy ekipie Sekuraka za fajny rabat dla naszej Społeczności!

...