Make brightness of two images same - python

I have two images:
How to make intensities/brightness of one image equal to other?

You can calculate the pictures brightness by following this procedure:
Calculate the brightness for each pixel by:
a. Converting them to grayscale, each pixel will hold a value between 0 and 255
b. Convert you image from RGB to HSV, where V refers to the brightness
Calculate overall brighness (sum of each pixel value divided by number of pixels)
Once calculated the brightness for both pictures, you can adjust it for one to be equal to the second picture.
EDIT
I strongly recommend using option 1b, as you will not loose color information, so you can convert back and forth. Using the grayscale variant, you will have to work on a copy of your image data.

Related

Stacking images together opencv python

So I am trying to make a single top down view from these 4 bird eye view images taken from 4 different cameras and after doing perspective transform, I just need to stack the 4 trapezoids together (without the green parts which are the walls).
the four images
example of what I want to achieve
first make your 4 images the same size by padding them with 0s while maintaining their position.
lets assume the top & bottom images are 150x50 and the left & right images are 50x100. So your final output image size will be 150x50+100+50=150x200. now do the math to figure out where to pad each image to keep their position.
now we need to remove the walls in each image and only keep the floor, you have two options from here:
Option 1:
Create a new black "mask" image for each image (same size 150x200). Now you can either manually get the location of the floor pixels or use color, and set the floor pixels in the mask to 255.
Now that you have the floor pixels mask for each image, you will need to copy those floor pixels over to your final output image. so create a new black image, for each mask, get the location of the non-zero pixels and copy the value of the pixels from the corresponding image over to your output image
Option 2:
Find the wall pixels in your images and set them to 0 then just add the images together.

Logic behind int16, uint8 etc. images

There is something that I probably misunderstand about data types in images. Lets say we have an uint8 image. Since uint8 is between 0 and 255, 0 is the darkest and 255 is the brightest intensity value.
Same logic would make -32768 the darkest and 32767 the brightest intensity value for an int16 image. However, I have an int16 image(it is originally a dicom) where the darkest pixel is -1024 and the brightest is 4095. I say int16 because pixels are saved in an int16 type numpy array.
In addition, when I concatenate two int16 numpy arrays where one of them is a = np.ones((100,100), dtype=np.int16) * 32767 and the other is b = np.ones((100,100), dtype=np.int16) * 32766 , It results in a binary image where 32767s is white and 32766s are black.
Can someone help me about what I am getting wrong?
Short answer
Nothing is wrong, this is how DICOM works.
Long answer
In DICOM standard, pixel value is not directly related to its color (gray level). These values should correspond to physical properties of the acquired item (e.g. in Computed Tomography pixel values are measured in Hounsfield Units. *(unless they are linearly rescaled, see below)).
Gray level of the pixel image is displayed dynamically based on arbitrary chosen minimal and maximal values, which are set by the user. Every pixel value less or equal minimum is black, every pixel greater or equal maximum is white, the others are linearly interpolated gray levels.
So it is perfectly fine that in binary image black minimum is equal to 32766 and white maximum is equal to 32767.
If you use DICOM viewer, you will have possibility to change dynamically these minimal and maximal values, so you will change total contrast and brightness of the image. It is necessary for radiologists, to diagnose e.g. lungs and bones in different ranges. And if you export DICOM to other file format, you should choose, what is the color mapping. Normally it is full range (the lowest value gets black, the brightest gets white).
There are two other values, which are often used instead of minimum and maximum: "window width" (ww) and "window level" (wl). ww = max-min, wl=(max+min)/2.
You should look at these questions and answers:
Window width and center calculation of DICOM image
*you should also consider tags "rescale intercept" (0028,1052), and "rescale slope" (0028,1053), that lineary rescale value of pixel array to the final value, but normally it is implemented in dicom toolkit.
FinalPixelValue = (RawPixelValue * RescaleSlope) + RescaleIntercept

How to get border pixels of an image in python?

I have an image, using steganography I want to save the data in border pixels only.
In other words, I want to save data only in the least significant bits(LSB) of border pixels of an image.
Is there any way to get border pixels to store data( max 15 characters text) in the border pixels?
Plz, help me out...
OBTAINING BORDER PIXELS:
Masking operations are one of many ways to obtain the border pixels of an image. The code would be as follows:
a= cv2.imread('cal1.jpg')
bw = 20 //width of border required
mask = np.ones(a.shape[:2], dtype = "uint8")
cv2.rectangle(mask, (bw,bw),(a.shape[1]-bw,a.shape[0]-bw), 0, -1)
output = cv2.bitwise_and(a, a, mask = mask)
cv2.imshow('out', output)
cv2.waitKey(5000)
After I get an array of ones with the same dimension as the input image, I use cv2.rectangle function to draw a rectangle of zeros. The first argument is the image you want to draw on, second argument is start (x,y) point and the third argument is the end (x,y) point. Fourth argument is the color and '-1' represents the thickness of rectangle drawn (-1 fills the rectangle). You can find the documentation for the function here.
Now that we have our mask, you can use 'cv2.bitwise_and' (documentation) function to perform AND operation on the pixels. Basically what happens is, the pixels that are AND with '1' pixels in the mask, retain their pixel values. Pixels that are AND with '0' pixels in the mask are made 0. This way you will have the output as follows:
.
The input image was :
You have the border pixels now!
Using LSB planes to store your info is not a good idea. It makes sense when you think about it. A simple lossy compression would affect most of your hidden data. Saving your image as JPEG would result in loss of info or severe affected info. If you want to still try LSB, look into bit-plane slicing. Through bit-plane slicing, you basically obtain bit planes (from MSB to LSB) of the image. (image from researchgate.net)
I have done it in Matlab and not quite sure about doing it in python. In Matlab,
the function, 'bitget(image, 1)', returns the LSB of the image. I found a question on bit-plane slicing using python here. Though unanswered, you might want to look into the posted code.
To access border pixel and enter data into it.
A shape of an image is accessed by t= img.shape. It returns a tuple of the number of rows, columns, and channels.A component is RGB which 1,2,3 respectively.int(r[0]) is variable in which a value is stored.
import cv2
img = cv2.imread('xyz.png')
t = img.shape
print(t)
component = 2
img.itemset((0,0,component),int(r[0]))
img.itemset((0,t[1]-1,component),int(r[1]))
img.itemset((t[0]-1,0,component),int(r[2]))
img.itemset((t[0]-1,t[1]-1,component),int(r[3]))
print(img.item(0,0,component))
print(img.item(0,t[1]-1,component))
print(img.item(t[0]-1,0,component))
print(img.item(t[0]-1,t[1]-1,component))
cv2.imwrite('output.png',img)

Using OpenCV Python, How would you make all black pixels transparent, and then overlay it over original image

I'm trying to make a colored mask, white.
And my idea is to:
make black pixels transparent in the mask
merge the two images
crop images
so then my original masked area will be white.
What kind of OpenCV python code/methods would I need?
Like so:
Original
Mask
Desired result (mocked up - no green edges)
Instead of
I suppose to do a color threshold to get the mask itself.
The result I got in a first quick and dirty attempt with Hue 43-81, Saturation 39-197 and Brightness from 115-255 is:
The next step is a whole fill algorithm to fill the inside of the mask. Note that also one small area to the right is selected.
The next step is a substraction of the two results (mask-filled_mask):
Again fill the wholes and get rid of the noisy pixels with binary opening:
Last mask the image with the created mask.
Every step can be adjusted to yield optimal results. A good idea is to try the steps out (for example with imageJ) to get your workflow set up and then script the steps in python/openCV.
Refer also to http://fiji.sc/Segmentation.
I am assuming your mask is a boolean numpy array and your 2 images are numpy arrays image1 and image2.
Then you can use the boolean array as multiplier.
overlay= mask*image1 + (-mask)*image2
So you get the "True" pixels from image1 and the False pixels from image2

What is a "twice HSV transformation"?

I learned this method from a SPIE Proceeding article, they used the twice HSV transformation for shadow detection. In their paper, the method was stated as following:
Firstly, the color model of the image is transformed from RGB to HSV,
and the three components of the HSV model are normalized to 0 to 255,
then the image is transformed from RGB to HSV once again. Thirdly, the
image is turned into a gray image from a color image, only the gray
value of the red component is used. Fourthly, the OTSU thresholding
method is used to produce a threshold by which the image is converted
to a binary image. Since the gray value of the shadow area is usually
smaller than those areas which are not covered by shadow, the
objective is pixels whose gray value is below the threshold, and
background is pixels whose gray value is beyond the threshold.
Do the second and third steps make sense?
The second and third statements absolutely don't make any sense whatsoever. Even the pipeline is rather suspicious. However, after re-reading that statement probably a dozen times, here is what I came up with. Apologies for any errors in understanding.
Let's start with the second point:
Firstly, the color model of the image is transformed from RGB to HSV, and the three components of the HSV model are normalized to 0 to 255, then the image is transformed from RGB to HSV once again
You're well aware that transforming an image from RGB to HSV results in another three channel output. Depending on which platform you're using, you'll either get 0-360 or 0-1 for the first channel or Hue, 0-100 or 0-255 for the second channel or Saturation, and 0-100 or 0-255 for the third channel or Value. Each channel may be unequal in magnitude when comparing with the other channels, and so these channels are normalized to the 0-255 range independently. Specifically, this means that the Hue, Saturation and Value components all get normalized so that they all span from 0-255.
Once we do this, we now have a HSV image where each channel ranges from 0-255. My guess is they call this new image a RGB image because the channels all span from 0-255, just like any 8-bit RGB image would. This also makes sense because when you're transforming an image from RGB to HSV, the dynamic range of the channels all span from 0-255, so my guess is that they normalize all of the channels in the first HSV result to make it suitable for the next step.
Once they normalize the channels after doing HSV conversion as per above, they do another HSV conversion on this new result. The reasons why they would do this a second time are beyond me and don't make any sense, but that's what I gathered from the above description, and that's what they probably mean by "twice HSV transformation" - To transform the original RGB image to HSV once, normalize that result so all channels span from 0-255, then re-apply the HSV conversion again to this intermediate result.
Let's go to the third point:
Thirdly, the image is turned into a gray image from a color image, only the gray value of the red component is used.
The output after you transform the HSV image a second time, the final result is simply taking the first channel which is inherently a grayscale image and is the "red" channel. Coincidentally, this also corresponds to the Hue after you do a HSV conversion. I'm not quite sure what properties the Hue channel holds after converting the image using HSV twice, but maybe it worked for this particular method.
I decided to give this a whirl and see if this really works. Here's an example image of a shadow I found online:
Source: http://petapixel.com/
The basic pipeline is to take an image, convert it into HSV, renormalize the image so that the values are 0-255 again, do another HSV conversion, then do an adaptive threshold via Otsu. We threshold below the optimal value to segment out the shadows.
I'm going to use OpenCV Python, as I don't have the C++ libraries set up on my computer here. In OpenCV, when converting an image to HSV, if the image is unsigned 8-bit RGB, the Saturation and Value components are automatically scaled to [0-255], but the Hue component is scaled to [0-179] in order to fit the Hue (which is originally [0-360)) into the data type. As such, I scaled each value by (255/179) so that the Hue gets normalized to [0-255]. Here's the code I wrote:
import numpy as np # Import relevant libraries
import cv2
# Read in image
img = cv2.imread('shadow.jpg')
# Convert to HSV
hsv1 = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# Renormalize Hue channel to 0-255
hsv1[:,:,0] = ((255.0/179.0)*hsv1[:,:,0]).astype('uint8')
# Convert to HSV again
# Remember, channels are now RGB
hsv2 = cv2.cvtColor(hsv1, cv2.COLOR_RGB2HSV)
# Extract out the "red" channel
red = hsv2[:,:,0]
# Perform Otsu thresholding and INVERT the image
# Anything smaller than threshold is white, anything greater is black
_,out = cv2.threshold(red, 0, 255, cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)
# Show the image - shadow mask
cv2.imshow('Output', out)
cv2.waitKey(0)
cv2.destroyAllWindows()
This is the output I get:
Hmm.... well there are obviously some noisy pixels, but I guess it does work.... kinda!

Categories