Intel® oneAPI DPC++/C++ Compiler
Talk to fellow users of Intel® oneAPI DPC++/C++ Compiler and companion tools like Intel® oneAPI DPC++ Library, Intel® DPC++ Compatibility Tool, and Intel® Distribution for GDB*
631 Discussions

different behavior when type casting from float to uchar

Nabeel-Kh
Beginner
640 Views

I am using dpc++ compiler integrated with microsoft visual studio, I wrote a small app to apply a filter to an image (gray scale), the app will compute the new value of the pixel on the device and store it on new filtered_image_buffer, while computing, the value is float and then it will be converted to uchar but the behavior is different when I use cpu vs gpu selector, on gpu the filter is applied correctly and the result image is fine, but in cpu the image is in chaos.
cpu that I am using: Intel(R) Core(TM) i7-8665U
gpu: Intel(R) UHD Graphics 620
here the results for gpu vs cpu (filter to sharpen the image is used)

NabeelKh_0-1714378957863.pngNabeelKh_1-1714378967550.png

 

code:
```

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

using namespace sycl;

int main(int argc, char* argv[]) {
cv::Mat image = cv::imread("oneapi1.png", cv::IMREAD_GRAYSCALE);
if (image.empty()) {
std::cout << "Could not open or find the image" << std::endl;
return -1;
}
std::vector<uchar> imageData;
imageData.assign(image.data, image.data + image.total());
buffer <uchar, 1> imageBuffer(imageData.data(), range<1>(image.total()));


cv::Mat filteredImage = image.clone();
std::vector<uchar> filteredImageData;
filteredImageData.assign(filteredImage.data, filteredImage.data + filteredImage.total() * filteredImage.channels());
cpu_selector selector;
queue q{ selector };
auto height = image.rows;
auto width = image.cols;
const int filterHeight = 5;
const int filterWidth = 5;
float filter[filterHeight][filterWidth] = {
{-1, -1, -1, -1, -1,},
{-1, 1.5, 1.5, 1.5, -1},
{-1, 1.5, 5, 1.5, -1},
{-1, 1.5, 1.5, 1.5, -1},
{-1, -1, -1, -1, -1}
};
buffer <float, 2> filterBuf(range<2>(filterHeight, filterWidth));
{
auto filterBufAcc = filterBuf.get_access<access::mode::read_write>();
for (int i = 0; i < filterHeight; i++) {
for (int j = 0; j < filterWidth; j++) {
filterBufAcc[i][j] = filter[i][j];
}
}
}

{
buffer <uchar, 1> filteredImageBuffer(filteredImageData.data(), range<1>(filteredImage.total() * filteredImage.channels()));
q.submit([&](handler& h) {
auto imageAcc = imageBuffer.get_access<access::mode::read>(h);
auto filteredImageAcc = filteredImageBuffer.get_access<>(h);
auto filterAcc = filterBuf.get_access<access::mode::read>(h);
h.parallel_for(range<2>{height - ((filterHeight / 2) * 2), width - ((filterWidth / 2) * 2)}, [=](item<2> id) {
float value = 0;
auto global_row = id.get_id(0) + (filterHeight / 2);
auto global_column = id.get_id(1) + (filterWidth / 2);
//filter need a special case for edges, but here it just skip them

for (int i = 0; i < filterHeight; i++) {
for (int j = 0; j < filterWidth; j++) {
value += filterAcc[i][j] * imageAcc[(id.get_id(0) + i) * width + id.get_id(1) + j];
}
}
filteredImageAcc[global_row * width + global_column] = (uchar)(value);
});
});
q.wait();
}

cv::Mat filteredImageResult(height, width, CV_8UC1, filteredImageData.data());
cv::namedWindow("filtered Image", cv::WINDOW_NORMAL);
cv::imshow("filtered Image", filteredImageResult);
cv::namedWindow("original Image", cv::WINDOW_NORMAL);
cv::imshow("original Image", image);
cv::waitKey(0);

return 0;
}
```
the original image is attached

0 Kudos
5 Replies
Alex_Y_Intel
Moderator
434 Views

Escalated to our engineering team for further investigation. 

0 Kudos
cw_intel
Moderator
421 Views

Can you tell us how to build your code? Which libraries of opencv need to be linked?


0 Kudos
Nabeel-Kh
Beginner
398 Views

I did more tests, and I could locate where the error come from, in gpu the device will directly convert the float to uchar, any negative value will become 0 and values over 255 will become 255. however the cpu don't do that directly for some reason and it typecast the float to int first then to uchar, and when typecasting int to uchar it will only take the first 8 bits and ignore all the others similar to as using "value%256", that what lead to wrong results, I could reproduce the same wrong results in gpu by typecasting the value(float) to int then to uchar.
the error isn't related to opencv, using uchar array with buffer and accessor to it will give same results.
not sure if the error considered from the compiler or from the code itself.

0 Kudos
cw_intel
Moderator
379 Views

Thank you for the details. Based on your description, I reproduced your issue with a small reproducer. And reported this issue to our internal team. Will let you know when there is any update.


0 Kudos
cw_intel
Moderator
94 Views


It is not an issue. It's undefined behavior since negative value and values over 255 can not be represented by unsigned char according to https://developercommunity.visualstudio.com/t/different-values-when-cast-negative-double-to-unsi/1161038#TPIN-N1166151.



0 Kudos
Reply