PySDL2 display grayscale numpy array on window surface - pysdl2

I have a grayscale image converted into numpy array.
I am trying to render this image on the sdl2 window surface.
sdl2.ext.init()
self.window = sdl2.ext.Window("Hello World!", size=(W, H))
self.window.show()
self.events = sdl2.ext.get_events()
for event in self.events:
if event.type == sdl2.SDL_QUIT:
exit(0)
self.windowsurface = sdl2.SDL_GetWindowSurface(self.window.window)
self.windowArray = sdl2.ext.pixels2d(self.windowsurface.contents)
self.windowArray[:] = frame[:,:,1].swapaxes(0,1)
self.window.refresh()
Right now I see the image in blue form. I want to render it as grayscale image. I have also tried to explore the sdl2.ext.colorpalettes but no success.
How can I display the grayscale numpy array on the sdl2 window surface

I've been playing around with this today, and from what I can tell the reason is a difference in dtypes, the surface is a numpy.uint32 while an image loaded from a gray scale image is only numpy.uint8. so full white in uint8 is 0xff when stored as auin32 it becomes 0x000000ff which is blue.
My dummy approach for testing is some numpy bit shifting:
self.windowArray[:] = self.windowArray[:] + (self.windowArray[:] << 8) + (self.windowArray[:] << 16)
I'm sure there is a better approach but at least it identifies the problem

Related

C++ How to make transparent watermark using OpenCV?

I am trying to make my watermark transparent with low opacity, but it seems just setting the colors to white:
This is the code I'm using which BTW I found in some website
/////////////////// Blending Images (Making Alpha) ////////////////////////
int main()
{
Mat img, img_bgra;
string img_path = "res/test.png";
img = imread(img_path);
if (img.data == NULL)
{
cout << "Image is not loaded!" << endl;
return -1;
}
cvtColor(img, img_bgra, ColorConversionCodes::COLOR_BGR2BGRA);
vector<Mat> channels(4);
split(img_bgra, channels);
channels[3] = channels[3] * 0.1;
merge(channels.data(), 4, img_bgra);
imwrite("res/transparent.png", img_bgra);
imshow("Image", img_bgra);
waitKey(0);
return 0;
}
I want the watermark to be displayed like this:
How can I achieve that?
i`m no good with C++, so i will try to explain with python example, hopefully this will be readable enough to help
alpha = 0.1 # maximum watermark opacity
imageSource = cv2.imread("res/test.png") # assuming BGR, uint8
imageWatermark = cv2.imread("res/transparent.png") # assuming BGRA, uint8
maskWatermark = imageWatermark[:,:, 3] # copy the alpha(transparency) channel, uint8
maskWatermark = np.float32(maskWatermark)*(1/255)*alpha # convert to float, normalize, apply transparency mul
maskSource = 1 -maskWatermark # float32, mask out the things we want to keep
imageWatermark = cv2.cvtColor(imageWatermark, cv2.COLOR_BGRA2BGR) # convert to same colorspace as source (3 channels), uint8
imageResult = np.uint8( np.float32(imageSource)*maskSource
+np.float32(imageWatermark)*maskWatermark)) # blend, convert to uint8
cv2.imshow('result', imageResult)
Key points here are:
some sort of mask is needed to tell which pixels of watermark are
going to affect the resulting image
blending is like interpolation between two color vectors, where
opacity acts like t-coordinate; this is done for each correspoinding
pixel pairs of two images
carefully watch data types to avoid overflow
images must be of same dimensions; if they`re not, you should shrink
or extend them in some way. I think that watermark is most likely is
much smaller than the image is. In this case you may want to copy the
watermarke part of the image (which matches watermark dimensions),
apply watermark and then copy back the watermarked fragment

How to remove the black border around rotated & masked image in result? OpenCv Python

I have the task of generating data for deep learning. I take seed images, rotate them and plot them randomly on a background. The issue is the rotation results in a broken line boundary around the image and I can't figure out why it appears or how to get rid of it.
def rotateSeed(img):
rotated = imutils.rotate_bound(img, randint(0,360))
for row in range(rotated.shape[0]):
for col in range(rotated.shape[1]):
if (rotated[row,col,0] == 0) and (rotated[row,col,1] == 0) and (rotated[row,col,2] == 0):
rotated[row,col] = default[0,0]
return rotated
Code explanation: default is the background color in the seed image. Rotation produces a black region I cover with the default.
Only one other person has had this problem and the solution does not explain much. It did not even rotate: OpenCV
Original seed image
Rotated seed image
You can use this code for rotation:
import cv2
import numpy as np
img = cv2.imread('C:\\Code\\1.jpeg')
num_rows, num_cols = img.shape[:2]
rotation_matrix = cv2.getRotationMatrix2D((num_cols/2, num_rows/2), 30, 1)
img_rotation = cv2.warpAffine(img, rotation_matrix, (num_cols, num_rows))
cv2.imshow('Rotation', img_rotation)
cv2.waitKey()

OpenCV load CIE L*a*b* image

I'm trying to load a CIE Lab* image using openCV in C++.
Online I can find only examples that load an RGB image and convert it into a LAB image but I already have the LAB image so how can I load it and than access to the values of L, a and b?
The only way I find is to load the LAB image considering it an RGB image and convert it into a Lab image using:
cvtColor(source, destination, CV_BGR2Lab);
But I think this is not a good way to solve the problem because if I do this, the converted image looks very different from the original.
With a test image and the following code:
originalImage = imread(originalImagePath, CV_LOAD_IMAGE_UNCHANGED);
cout << originalImage.type() << endl;
Mat originalImageSplitted[3];
split(originalImage, originalImageSplitted);
cout << originalImageSplitted[0] << endl;
cout << originalImageSplitted[1] << endl;
cout << originalImageSplitted[2] << endl;
I get the result:
0
[]
[]
[]
Not really an answer, but too much for a comment.
You can make a Lab colourspace TIF file for testing like this with ImageMagick from the Terminal in Linux, macOS or Windows:
convert -depth 8 xc:black xc:white xc:red xc:lime xc:blue +append -colorspace Lab result.tif
That will look like this if I scale it up as it is currently only 5 pixels wide and 1 pixel tall:
You can then dump the pixels to see their values and hopefully work out what OpenCV is doing:
convert result.tif txt:
Sample Output
# ImageMagick pixel enumeration: 5,1,65535,cielab
0,0: (0,-0.5,-0.5) #000000 cielab(0%,-0.000762951%,-0.000762951%) <--- black pixel
1,0: (65535,-0.5,-0.5) #FF0000 cielab(100%,-0.000762951%,-0.000762951%) <--- white pixel
2,0: (34952,20559.5,17218.5) #885043 cielab(53.3333%,31.3718%,26.2737%) <--- red pixel
3,0: (57568,-22102.5,21330.5) #E00053 cielab(87.8431%,-33.7263%,32.5483%) <--- green pixel
4,0: (21074,20302.5,-27756.5) #524F00 cielab(32.1569%,30.9796%,-42.3537%) <--- blue pixel
Looking at the red pixel, you get:
L=53.33%
a=31.37% of 256, i.e. 80.3
b=26.27% of 256, i.e. 67.2
To keep the image unchanged you should read it into a Mat image similarly:
Mat image;
image = imread(<path_of_image>, CV_LOAD_IMAGE_UNCHANGED)
In this case the second argument should preserve your image color channels as is.
With #DanMaĆĄek using #MarkSetchell image we solved the problem.
Using imread function the image is automatically converted into an RGB image so it's needed to convert it into a Lab image again.
Another problem is releated to 8bit images. The resulted image has modified values of L,a and b following this rule:
L * 255/100
a as a+128
b as b+128
So I solved doing the following:
originalImage = imread(originalImagePath, CV_LOAD_IMAGE_UNCHANGED);
Mat originalImageLab;
cvtColor(originalImage, originalImageLab, COLOR_RGB2Lab);
Mat originalImageSplitted[3];
split(originalImageLab, originalImageSplitted);
Thank you all!

Animated transition/wipe using SDL2 and black/white mask?

I've been tearing my hair out over how to do this simple effect. I've got an image (see below), and when this image is used in a game, it produces a clockwise transition to black effect. I have been trying to recreate this effect in SDL(2) but to no avail. I know it's got something to do with masking but I've no idea how to do that in code.
The closest I could get was by using "SDL_SetColorKey" and incrementing the RGB values so it would not draw the "wiping" part of the animation.
Uint32 colorkey = SDL_MapRGBA(blitSurf->format,
0xFF - counter,
0xFF - counter,
0xFF - counter,
0
);
SDL_SetColorKey(blitSurf, SDL_TRUE, colorkey);
// Yes, I'm turning the surface into a texture every frame!
SDL_DestroyTexture(streamTexture);
streamTexture = SDL_CreateTextureFromSurface(RENDERER, blitSurf);
SDL_RenderCopy(RENDERER, streamTexture, NULL, NULL);
I've searched all over and am now just desperate for an answer for my own curiosity- and sanity! I guess this question isn't exactly specific to SDL; I just need to know how to think about this!
Arbitrarily came up with a solution. It's expensive, but works. By iterating through every pixel in the image and mapping the colour like so:
int tempAlpha = (int)alpha + (speed * 5) - (int)color;
int tempColor = (int)color - speed;
*pixel = SDL_MapRGBA(fmt,
(Uint8)tempColor,
(Uint8)tempColor,
(Uint8)tempColor,
(Uint8)tempAlpha
);
Where alpha is the current alpha of the pixel, speed is the parameterised speed of the animation, and color is the current color of the pixel. fmt is the SDL_PixelFormat of the image. This is for fading to black, the following is for fading in from black:
if ((255 - counter) > origColor)
continue;
int tempAlpha = alpha - speed*5;
*pixel = SDL_MapRGBA(fmt,
(Uint8)0,
(Uint8)0,
(Uint8)0,
(Uint8)tempAlpha
);
Where origColor is the color of the pixel in the original grayscale image.
I made a quick API to do all of this, so feel free to check it out: https://github.com/Slynchy/SDL-AlphaMaskWipes

How to apply overlay transparency to RGBA image

Here's my dilemma: I have to RGBA RAW images: a master image (the first) and a subtitle track (the second), and I want to overlay them in a way based on the alpha channel of the second image: If it's zero, then take the pixels from the second image, if it's 0xFF take the pixels from the first image, otherwise create an overlay of the second image on the first one. Here's the code used for this:
if(frame->bytes[pc + 3] == 0xFF) /* this is NO transparency in the overlay image, meaning: take over the overlay 100% */
{
pFrameRGB->data[0][pc] = frame->bytes[pc]; // Red
pFrameRGB->data[0][pc+1] = frame->bytes[pc+1];// Green
pFrameRGB->data[0][pc+2] = frame->bytes[pc+2];// Blue
}
else
if(frame->bytes[pc + 3] != 0) /* this is full transparency in the overlay image, meaning: take over the image 100% */
{
pFrameRGB->data[0][pc] |= frame->bytes[pc]; // Red
pFrameRGB->data[0][pc+1] |= frame->bytes[pc+1];// Green
pFrameRGB->data[0][pc+2] |= frame->bytes[pc+2];// Blue
pFrameRGB->data[0][pc+3] = frame->bytes[pc+3]; // Alpha
}
In the code above the pFrameRGB is the target RGBA image, already containing somet image there, frame->bytes is the "overlay/subtitle" image ... And here comes my question: with some colourful overlay/subtitle images the destination is too colourful... so it's not like the subtitle image is overlayed which effect I want to obtain but you can see a whole range of colors (For example: I have a red/green overlay image with an increasing alpha and I would like the overlay image to look like a "pale" red/green overlay with image below it, however with the approach above I get a lot of colourful pixels on the image below). Do you have a somewhat better approach to this?
Thanks,
fritzone
An equation for doing alpha blending is more complex than just a bitwise or. Supposing a linear response model for RGB a quite common implementation is:
dst_R = (src_R*src_A + dst_R*(255 - src_A)) / 255;
dst_G = (src_G*src_A + dst_G*(255 - src_A)) / 255;
dst_B = (src_B*src_A + dst_B*(255 - src_A)) / 255;
dst_A = min(src_A + dst_A, 255);