skimage convert to grayscale resulting to a black image - python

I am scraping image and trying to convert them into grayscale. But if i view the image. It is plain black. Can someone tell me what is wrong with this? Thanks
Here is my snippet
import cv2
from skimage import io
from skimage import data
from skimage.color import rgb2gray
#...some codes
for i in elements:
try:
i.click()
except ElementClickInterceptedException:
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
i.click()
url = driver.find_element_by_xpath('//*[#class="slider-list"]/div/img').get_attribute('src').replace('height=600','height=1200').replace('quality=70','quality=100')
print (url)
name = driver.find_element_by_xpath('//*[#class="slider-list"]/div/img').get_attribute('alt') + '.jpg'
print (name)
img = io.imread(url)
new = rgb2gray(img)
cv2.imwrite(os.path.join(fldrnm, name), new)

Import cv2
Img = cv2.inread(filepath)
Img = cv2.cvtColor(Img, cv2.COLOR_RGB2GRAY)
cv2.imwrite(path,img)

The original cause of the problem is that skimage.color.rgb2gray will rescale an image to floating point values in [0, 1], even if the original image contains uint8 values in [0, 255]. This is done to preserve precision during long sequences of operations. Using skimage.io.imsave instead of cv2.imwrite in the original question would work, as well as using skimage.util.img_as_ubyte before saving.
See this page for more details:
https://scikit-image.org/docs/dev/user_guide/data_types.html

Related

Problem to recognize characters in Pytesseract python

I'm woorking with this kind of image Original_Image and I'm having some problems to apply character recognition. I'm tried some image treatment (gray, black and white, noise removal,..) and got only bad results. This is a part of the code I'm work in Python.
import cv2
from matplotlib import pyplot as plt
import pytesseract
pytesseract.pytesseract.tesseract_cmd = r"C:\Users\14231744700\AppData\Local\Tesseract-OCR\tesseract.exe"
image_file = '5295_down.bmp'
img = cv2.imread(image_file)
height,width,channels= img.shape
#The attached image is this one (img_cropped) and I want this data as a string to work on it
img_cropped = img[41*height//50:92*height//100,2*width//14:81*width//100]
#cv2.imshow('Image_cropped', img_cropped)
#cv2.imwrite('image_cropped.png', img_cropped)
#cv2.waitKey(0)
def image_to_string(image):
data = pytesseract.image_to_string(image, lang='eng', config='--psm 6')
return data
image_to_string(img_cropped)
If someone know about a preprocessing step or any other possibility to get better results, I'll be very thankfull.

Python add noise to image breaks PNG

I'm trying to create a image system in Python 3 to be used in a web app. The idea is to load an image from disk and add some random noise to it. When I try this, I get what looks like a totally random image, not resembling the original:
import cv2
import numpy as np
from skimage.util import random_noise
from random import randint
from pathlib import Path
from PIL import Image
import io
image_files = [
{
'name': 'test1',
'file': 'test1.png'
},
{
'name': 'test2',
'file': 'test2.png'
}
]
def gen_image():
rand_image = randint(0, len(image_files)-1)
image_file = image_files[rand_image]['file']
image_name = image_files[rand_image]['name']
image_path = str(Path().absolute())+'/img/'+image_file
img = cv2.imread(image_path)
noise_img = random_noise(img, mode='s&p', amount=0.1)
img = Image.fromarray(noise_img, 'RGB')
fp = io.BytesIO()
img.save(fp, format="PNG")
content = fp.getvalue()
return content
gen_image()
I have also tried using pypng:
import png
# Added the following to gen_image()
content = png.from_array(noise_img, mode='L;1')
content.save('image.png')
How can I load a png (With alpha transparency) from disk, add some noise to it, and return it so that it can be displayed by web server code (flask, aiohttp, etc).
As indicated in the answer by makayla, this makes it better: noise_img = (noise_img*255).astype(np.uint8) but the colors are still wrong and there's no transparency.
Here's the updated function for that:
def gen_image():
rand_image = randint(0, len(image_files)-1)
image_file = image_files[rand_image]['file']
image_name = image_files[rand_image]['name']
image_path = str(Path().absolute())+'/img/'+image_file
img = cv2.imread(image_path)
cv2.imshow('dst_rt', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
# Problem exists somewhere below this line.
img = random_noise(img, mode='s&p', amount=0.1)
img = (img*255).astype(np.uint8)
img = Image.fromarray(img, 'RGB')
fp = io.BytesIO()
img.save(fp, format="png")
content = fp.getvalue()
return content
This will popup a pre-noise image and return the noised image. RGB (And alpha) problem exists in returned image.
I think the problem is it needs to be RGBA but when I change to that, I get ValueError: buffer is not large enough
Given all the new information I am updating my answer with a few more tips for debugging the issue.
I found a site here which creates sample transparent images. I created a 64x64 cyan (R=0, G=255, B=255) image with a transparency layer of 0.5. I used this to test your code.
I read in the image two ways to compare: im1 = cv2.imread(fileName) and im2 = cv2.imread(fileName,cv2.IMREAD_UNCHANGED). np.shape(im1) returned (64,64,3) and np.shape(im2) returned (64,64,4). This is why that flag is required--the default imread settings in opencv will read in a transparent image as a normal RGB image.
However opencv reads in as BGR instead of RGB, and since you cannot save out with opencv, you'll need to convert it to the correct order otherwise the image will have reversed color. For example, my cyan image, when viewed with the reversed color appears like this:
You can change this using openCV's color conversion function like this im = cv2.cvtColor(im, cv2.COLOR_BGRA2RGBA) (Here is a list of all the color conversion codes). Again, double check the size of your image if you need to, it should still have four channels since you converted it to RGBA.
You can now add your noise to your image. Just so you know, this is also going to add noise to your alpha channel as well, randomly making some pixels more transparent and others less transparent. The random_noise function from skimage converts your image to float and returns it as float. This means the image values, normally integers ranging from 0 to 255, are converted to decimal values from 0 to 1. Your line img = Image.fromarray(noise_img, 'RGB') does not know what to do with the floating point noise_img. That's why the image is all messed up when you save it, as well as when I tried to show it.
So I took my cyan image, added noise, and then converted the floats back to 8 bits.
noise_img = random_noise(im, mode='s&p', amount=0.1)
noise_img = (noise_img*255).astype(np.uint8)
img = Image.fromarray(noise_img, 'RGBA')
It now looks like this (screenshot) using img.show():
I used the PIL library to save out my image instead of openCV so it's as close to your code as possible.
fp = 'saved_im.png'
img.save(fp, format="png")
I loaded the image into powerpoint to double-check that it preserved the transparency when I saved it using this method. Here is a screenshot of the saved image overlaid on a red circle in powerpoint:

Image loaded wrong by opencv

Disaster!
As you can see, the image isn't quite loaded correctly. The original:
The code:
import cv2
import imutils
a=imutils.url_to_image("https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png", readFlag=-1)
cv2.imshow("goog", a)
cv2.waitKey()
The implementation of url_to_image in imutils:
def url_to_image(url, readFlag=cv2.IMREAD_COLOR):
# download the image, convert it to a NumPy array, and then read
# it into OpenCV format
resp = urlopen(url)
image = np.asarray(bytearray(resp.read()), dtype="uint8")
image = cv2.imdecode(image, readFlag)
# return the image
return image
I also tried readFlag=cv2.IMREAD_UNCHANGED, but that didn't do the trick either.
please send help
alright gang we did it
so I tried another version of displaying:
plt.figure("Correct")
plt.imshow(imutils.opencv2matplotlib(a))
plt.show()
No luck it would appear. But then, looking into the opencv2matplotlib source, we find:
def opencv2matplotlib(image):
# OpenCV represents images in BGR order; however, Matplotlib
# expects the image in RGB order, so simply convert from BGR
# to RGB and return
return cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
Aha, but we have 4 channel color (alpha), so by common sense we need cv2.COLOR_BGRA2RGBA not cv2.COLOR_BGR2RGB!!
Testing this theory:
plt.figure("Correct")
plt.imshow(cv2.cvtColor(a, cv2.COLOR_BGRA2RGBA))
plt.show()
We get...
Whoop dee doop!
# import the necessary packages
import numpy as np
import urllib
import cv2
def url_to_image(url):
# download the image, convert it to a NumPy array, and then read
# it into OpenCV format
resp = urllib.request.urlopen(url)
image = np.asarray(bytearray(resp.read()), dtype="uint8")
image = cv2.imdecode(image, cv2.IMREAD_COLOR)
# return the image
return image
# initialize the list of image URLs to download
url="http://i.dailymail.co.uk/i/pix/2015/09/01/18/2BE1E88B00000578-3218613-image-m-5_1441127035222.jpg"
print ("downloading %s" % (url))
image = url_to_image(url)
cv2.imshow("Image", image)
cv2.waitKey(0)
And the output is:

Want to append colored images to a list and convert that list to grayscale using OpenCV

So basically I'm trying to convert a set of RGB images to grayscale using cv2.cvtColor and python is throwing the following error:
Traceback (most recent call last):
File "MCG.py", line 53, in
gray = cv2.cvtColor(data, cv2.COLOR_BGR2GRAY)
TypeError: src is not a numpy array, neither a scalar.
This here is the code:
import numpy as np
import cv2
import dlib
import sys
import skimage
from PIL import Image
import os
import glob
folderpath = sys.argv[1]
cascPath = sys.argv[2]
imageformat = ".tif"
path = folderpath
imfilelist = [os.path.join(path,f) for f in os.listdir(path) if f.endswith(imageformat)]
data = []
for IMG in imfilelist:
print IMG
image = cv2.imread(IMG)
data.append(image)
cv2.imshow('Image', image)
cv2.waitKey(0)
faceCascade = cv2.CascadeClassifier(cascPath)
predictor = dlib.shape_predictor(PREDICTOR_PATH)
gray = cv2.cvtColor(data, cv2.COLOR_BGR2GRAY)
faces = faceCascade.detectMultiScale(
gray,
scaleFactor=1.05,
minNeighbors=5,
minSize=(100,100)
)
As you can see, I'm trying to append all these images to a list, which will then be converted using the cv2.cvtColor function. However, that error is thrown. What am I doing wrong? Thank you.
P.S if anyone is wondering why I imported modules that don't seem to be used in this code, this code is just a segment of the whole thing and all of those modules have are being utilized in one way or the other.
If you read the cv2.cvtColor documentation, you can see that the first parameter is the Src 8-bit single channel image. However, in your case you are giving an entire list of images.
So change the code as
gray = []
for j in range(0,len(data)):
gray.append(cv2.cvtColor(np.array(data[j]), cv2.COLOR_BGR2GRAY))
I guess this should work.
You are collecting the images into a list with
data = []
for IMG in imfilelist:
...
data.append(image)
....
and then trying to convert the list with
gray = cv2.cvtColor(data, cv2.COLOR_BGR2GRAY)
This is why you are getting the error - the error is telling you that data is not an image (numpy array) but is a list. You need to convert one image at a time with cv2.cvtColor().
You could try
gray = []
for img in data:
gray.append(cv2.cvtColor(img, cv2.COLOR_BGR2GRAY))
This would give you a list of greyscaled images, which is what I think you want to do.

How can i read input only a part of the image without creating another image?

import cv2
fname = '1.png'
img=cv2.imread(fname, 0)
print (img)//the outcome is an array of values from 0 to 255 (grayscale)
ret, thresh = cv2.threshold(img, 254, 255, cv2.THRESH_BINARY)
thresh = cv2.bitwise_not(thresh)
nums, labels = cv2.connectedComponents(thresh, None, 4, cv2.CV_32S)
dst = cv2.convertScaleAbs(255.0*labels/nums)
cv2.imwrite(dest_dir+"output.png", dst)
that code works just fine, so i moved on to adjusting my code so it can take a portion of the image not the entire image:
from PIL import Image
img = Image.open(fname)
img2 = img.crop((int(xmin), int(yMin),int(xMax), int(yMax))
xmin ymin xmax ymax simply being the top left bottom right coordinates of the box.
then i did img = cv2.imread(img2) to continue as the previous code but got an error, i printed img2 and got <PIL.Image.Image image mode=RGB size=54x10 at 0x7F4D283AFB70> how can i adjust it to be able to input that crop or image portion instead of fname in my code above, and kindly note i don't want to save img2 as an image and carry on from there because i need to work on the main image.
try cv2.imshow() instead of printing it. In order to see an image you cropped, you need to use cv2 function. here is a sample code:
import numpy as np
import cv2
# Load an color image in grayscale
img = cv2.imread('messi5.jpg',0)
cv2.imshow('image',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
The simple answer is NO you cannot.
Open up your terminal /IDE and type in help(cv2.imread).
It clearly states that The function imread loads an image from the specified file and returns it. So in order to use cv2.imread() you must pass it in as a file not an image.
Your best bet would be to save your cropped image as a file and then read it.

Categories