Remove black areas in image with alpha, odd result, Python opencv - python

file_name = "alpha_sample.png"
src = cv2.imread(file_name, 1)
tmp = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)
_,alpha = cv2.threshold(tmp,0,255,cv2.THRESH_BINARY)
b, g, r = cv2.split(src)
rgba = [b,g,r, alpha]
dst = cv2.merge(rgba,4)
#cv2.imshow('funny',dst)
cv2.imwrite("Result.png", dst)
I am trying to run this short code sample (credits by User: Srikanth Bhandary). The Input image is an image with two black rectangles at the bottom.
Input image
Result image
I want to make these areas transparent. But the result of the code is the image below. The code seems to divide the image quite random in a transparent an a non transparent part.
Any suggestions?
Regards, Tobias

Related

Python - replicating the GIMP's "Erase color" blend mode

I'm looking for a way to recreate the GIMP's Erase color blending mode in Python 3 & OpenCV2.
I know it's possible to erase color using the that library, but the code I run works on exactly one of them. Furthermore, I don't believe such small amount of code could do that advanced thing.
Looking for a solution, I found the blend-modes by flrs, but it also doesn't include the option I want.
Sadly, I have no experience in OpenCV2 at the moment, but I think developing such thing could be very helpful.
Can someone guide me how to make this more reliable, or is it even possible to do with things that I've got already?
OpenCV2 color removal
Code
import cv2
from PIL import Image
#-=-=-=-#
File_Name = r"Spectrogram.png"
SRC = cv2.imread(File_Name, 1)
TMP = cv2.cvtColor(SRC, cv2.COLOR_BGR2GRAY)
_, A = cv2.threshold(TMP, 0, 255, cv2.THRESH_BINARY)
B, G, R = cv2.split(SRC)
Colors = [B, G, R, A]
Picture = cv2.merge(Colors, 4)
#-=-=-=-#
# My CV2 image display doesn't include transparency
im = cv2.cvtColor(Picture, cv2.COLOR_BGR2RGB)
im = Image.fromarray(im)
im.show()
Result
Original
Result
GIMP Erase color blending-mode
Type
Background
Foreground
Result
Image
Blending
Normal
Erase color
Normal
Here is one simple way in Python/OpenCV.
Read the input
Choose a color range
Apply range to threshold the image
Invert the range as a mask to be used later for the alpha channel
Convert the image from BGR to BGRA
Put mask into the alpha channel of the BGRA image
Save the result
Input:
import cv2
import numpy as np
# load image and set the bounds
img = cv2.imread("red_black.png")
# choose color range
lower =(0,0,0) # lower bound for each BGR channel
upper = (140,0,190) # upper bound for each BRG channel
# create the mask
mask = cv2.inRange(img, lower, upper)
# invert mask
mask = 255 - mask
# convert image to BGRA
result = cv2.cvtColor(img, cv2.COLOR_BGR2BGRA)
# put mask into alpha channel
result[:,:,3] = mask
# write result to disk
cv2.imwrite("red_black_color_removed.png", result)
# display it (though does not display transparency properly)
cv2.imshow("mask", mask)
cv2.imshow("results", result)
cv2.waitKey(0)
Result:

How to overlay only the needed image?

I have two images.
Image 1:
Image 2:
Both the images have the same resolution. I want to overlay the second image on the first image.
This is what I tried:
from PIL import Image
img1 = Image.open("D:\\obj1__0.png")
img1 = img1.convert("RGBA")
img1 = img1.resize((640,360))
img2 = Image.open('D:\\Renderforest_Watermark.png')
img2 = img2.convert("RGBA")
img2 = img2.resize((640,360))
new_img = Image.blend(img1,img2,0.7)
new_img.save("D:\\Final.png")
Output:
My Question: How do I overlay image 2 on image 1 such that only the watermark is overlaid?
P.S: I already searched for this on Stack Overflow, but couldn't find any answers.
Your overlay image is incorrectly formed. It should be transparent where it is white. It has no transparency, so it isn't see-through. I can only suggest to make a synthetic alpha channel by guessing that it should be transparent where the overlay image is white:
#!/usr/bin/env python3
from PIL import Image
# Set a common size
size = (640, 360)
# Load background and overlay, removing the pointless alpha channel and resizing to a common size
bg = Image.open('background.png').convert('RGB').resize(size)
overlay = Image.open('overlay.png').convert('RGB').resize(size)
# Try and invent a mask by making white pixels transparent
mask = overlay.convert('L')
mask = mask.point(lambda p: 255 if p < 225 else 0)
# Paste overlay onto background only where the mask is, then save
bg.paste(overlay, None, mask)
bg.save('result.png')
If your image did have an alpha channel, you would avoid deleting the original alpha channel and open it like this instead:
overlay = Image.open('overlay.png').resize(size)
then delete these lines:
# Try and invent a mask by making white pixels transparent
mask = overlay.convert('L')
mask = mask.point(lambda p: 255 if p < 225 else 0)
then change the line after the above to:
# Paste overlay onto background only where the mask is, then save
bg.paste(overlay, None, overlay)
Keywords: Image processing, PIL, Pillow, overlay, watermark, transparent, alpha.

Convert Gray background to white background without disturbing the original image

I have cropped few images which have gray back ground and need to convert them to white back ground to compare with Reference images.
The following code I implemented to convert:
import cv2
im_gray = cv2.imread('gray_bg.png', cv2.IMREAD_GRAYSCALE)
(thresh, im_bw) = cv2.threshold(im_gray, 255, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
cv2.imwrite('white_bg.png', im_bw)
input:
output:
expected output:
If you observe, my output image has some noise in edges of the original image (I hope I am not wrong in saying). Because of this, while comparing my output with Reference images, I am not getting the desired output. Can someone suggest me how to do it?
Here is the program We wrote to compare two images:
SourceImagePath = r'white_bg.png'
TemplateImagePath = r'ex_white_bg.png'
#def IconValidation(self,SourceImagePath,TemplateImagePath):
sourceImg=cv.imread(SourceImagePath)
templateImg=cv.imread(TemplateImagePath)
_,tempwidth,tempheight=templateImg.shape[::-1]
srcheight = np.size(sourceImg, 0)
srcwidth = np.size(sourceImg, 1)
if(srcwidth < tempwidth) and (srcheight < tempheight):
print("comparison")
resultImg = cv.matchTemplate(sourceImg,templateImg,cv.TM_CCOEFF_NORMED)
matchVal = resultImg[0][0]
threshold=0.95
if(matchVal>threshold):
print("passed")
else:
print("failed")
What you see is aliasing, not noise. It appears because of hard thresholding.
You input image does have a little noise, which you see by enlarging (possibly due to lossy compression at some stage), but it is not aliased.
You can turn the gray background to white while keeping the black by applying a gain of 1.4 (the gray level is around 180). This will avoid the introduction of aliasing.
Avoiding the change of color encoding achive the best results. Here is the code:
im_gray = cv2.imread('gray_bg.png', cv2.IMREAD_UNCHANGED)
b, g, r = cv2.split(im_gray)
t = [None] * 3
u = [None] * 3
for i, im in enumerate([b, g, r]):
t[i], u[i] = cv2.threshold(im, 255, 255, cv2.THRESH_BINARY + cv2.THRESH_TRIANGLE)
dst = cv2.merge((*u,))
cv2.imwrite('white_bg.png', dst)
By comparing it with the original it gives 99.99% equality.
Than if you really need it you can convert the image to grayscale encoding with cv2.cvtColor(src, cv2.COLOR_BGR2GRAY).
Result vs Wanted:

I want to increase brightness and contrast of images in dynamic way so that the program is applicable for any new images

I have few images where I need to increase or decrease the contrast and brightness of the image in a dynamic way so that it is visible clearly. And the program needs to be dynamic so that it even works for new images also. I also want character should be dark.
I was able to increase brightness and contrast but it is not working properly for each image.
import cv2
import numpy as np
img = cv2.imread('D:\Bright.png')
image = cv2.GaussianBlur(img, (5, 5), 0)
#image = cv2.threshold(image, 0, 255, cv2.THRESH_BINARY)[1]
#kernel = np.ones((2,1),np.uint8)
#dilation = cv2.dilate(img,kernel)
cv2.imshow('test', image)
cv2.waitKey(0)
cv2.destroyAllWindows()
imghsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
imghsv[:,:,2] = [[max(pixel - 25, 0) if pixel < 190 else min(pixel + 25, 255) for pixel in row] for row in imghsv[:,:,2]]
cv2.imshow('contrast', cv2.cvtColor(imghsv, cv2.COLOR_HSV2BGR))
#cv2.imwrite('D:\\112.png',cv2.cvtColor(imghsv, cv2.COLOR_HSV2BGR))
cv2.waitKey(0)
cv2.destroyAllWindows()
#raw_input()
I want a program which works fine for every image and words are a little darker so that they are easily visible.
As Tilarion suggested, you could try "Auto Brightness And Contrast" to see if it works well. The theory behind this is explained well here in the solution section. The solution is in C++. I've written a version of it in python which you can directly use, works only on 1 channel at a time for colour images:
def auto_brightandcontrast(input_img, channel, clip_percent=1):
histSize=180
alpha=0
beta=0
minGray=0
maxGray=0
accumulator=[]
if(clip_percent==0):
#min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(hist)
return input_img
else:
hist = cv2.calcHist([input_img],[channel],None,[256],[0, 256])
accumulator.insert(0,hist[0])
for i in range(1,histSize):
accumulator.insert(i,accumulator[i-1]+hist[i])
maxx=accumulator[histSize-1]
minGray=0
clip_percent=clip_percent*(maxx/100.0)
clip_percent=clip_percent/2.0
while(accumulator[minGray]<clip_percent[0]):
minGray=minGray+1
maxGray=histSize-1
while(accumulator[maxGray]>=(maxx-clip_percent[0])):
maxGray=maxGray-1
inputRange=maxGray-minGray
alpha=(histSize-1)/inputRange
beta=-minGray*alpha
out_img=input_img.copy()
cv2.convertScaleAbs(input_img,out_img,alpha,beta)
return out_img
It is a very few lines of code to do it in Python Wand (which is based upon ImageMagick). Here is a script.
#!/bin/python3.7
from wand.image import Image
with Image(filename='task4.jpg') as img:
img.contrast_stretch(black_point=0.02, white_point=0.99)
img.save(filename='task4_stretch2_99.jpg')
Input:
Result:
Increase the black point value to make the text darker and/or decrease the white point value to make the lighter parts brighter.
Thanks to Eric McConville (the Wand developer) for correcting my arguments to make the code work.

Improve image quality using python

i have some problem with my task. i need get text from image using python+tesseract. But quality of image it's not highter - it`s screenshoot.
I'm using OpenCV lib and have two variant`s:
COLOR_BGR2GRAY
ADAPTIVE_THRESH_GAUSSIAN_C | THRESH_BINARY
and this variant`s working incorrect.
When i binarize image
def binarize_image(img_path, threshold=195):
"""Binarize an image."""
image_file = Image.open(img_path)
image = image_file.convert('L') # convert image to monochrome
image = np.array(image)
image = binarize_array(image, threshold)
im = Image.fromarray(image)
im.save(img_path)
# imsave(target_path, image)
def binarize_array(numpy_array, threshold=250):
"""Binarize a numpy array."""
for i in range(len(numpy_array)):
for j in range(len(numpy_array[0])):
if numpy_array[i][j] > threshold:
numpy_array[i][j] = 255
else:
numpy_array[i][j] = 0
return numpy_array
tesseract doesn`t usualy get text.
How i can resolve it`s problem ?
screenshot example
UPD: solved my problem, i need to add some pixels between two letters. on screenshot letter is white and background is black. How i can do it using numpy ?

Categories