I have used a tutorial to program this Image to ASCII Art converter, but it gives me an error. Here is the code:
import PIL.Image
from tkinter import filedialog
# Ascii characters
ASCII_CHARS = ["#", "#" ,"S" ,"%" ,"?" ,"*" ,"+" , ";", ":", "," "."]
def resize_image(image,new_width=100):
width,height =image.size
ratio = height / width / 1.65
new_height = int(new_width*ratio)
resized_image = image.resize((new_width,new_height))
return(resized_image)
# convert each pixel to grayscale
def grayscaler(image):
grayscale_image = image.convert("L")
return(grayscale_image)
#convert pixels to a string of ASCII characters
def pixels_to_ascii(image):
pixels = image.getdata()
characters = "".join([ASCII_CHARS[pixel // 25]for pixel in pixels])
return(characters)
def main(new_width=100):
# Get image path
path = filedialog.askopenfilename(title="Select an image", filetypes=(("Image File", "*.png"),("all files", "*.*")))
try:
image = PIL.Image.open(path)
except:
print(path, "is not a valid pathname to an image")
# convert image to ascii
new_image_data = pixels_to_ascii(grayscaler(resize_image(image)))
# format
pixel_count = len(new_image_data)
ascii_image = "\n".join(new_image_data[i:(i+new_width)] for i in range(0, pixel_count, new_width))
# print result
print(ascii_image)
# save result to "ascii_image.txt"
with open("ascii_image.txt", "w") as f:
f.write(ascii_image)
main()
It is suposed to be printing and saving the ascii art. Instead of that, it gives me this error ay line 34, and 22:
Traceback (most recent call last):
File "c:\Users\Forna\Documents\PYTHON\Image to Ascii\main.py", line 47, in <module>
main()
File "c:\Users\Forna\Documents\PYTHON\Image to Ascii\main.py", line 34, in main
new_image_data = pixels_to_ascii(grayscaler(resize_image(image)))
File "c:\Users\Forna\Documents\PYTHON\Image to Ascii\main.py", line 22, in pixels_to_ascii
characters = "".join([ASCII_CHARS[pixel // 25]for pixel in pixels])
File "c:\Users\Forna\Documents\PYTHON\Image to Ascii\main.py", line 22, in <listcomp>
characters = "".join([ASCII_CHARS[pixel // 25]for pixel in pixels])
IndexError: list index out of range
It would be very nice if someone could help me.
The error was in
ASCII_CHARS = ["#", "#" ,"S" ,"%" ,"?" ,"*" ,"+" , ";", ":", "," "."]
There wasn't a , after "," my bad
Related
I'm trying to write a program in Python that takes an image and replaces the pixels with images, based off of the pixels lightness value. Figured I'd start with following a tutorial on converting images to ASCII art, then I can replace the ASCII characters with images. Here's what this attempt looks like:
https://pastebin.com/VNFWd9xN
It's a bit quick and dirty, just to see if I can make it work, but I think you'll get the idea.
So, a couple of issues I ran into.
The first and biggest one, i get a "TypeError: sequence item 0: expected str instance, JpegImageFile found". I get that the program expects a string and gets an image instead. But, how do I solve that?
Lastly, more of a parenthesis really, but I was playing around with the save function and could not get it so save "ascii_image" to jpg.
Anyhow, would really appreciate some guidance here.
Thank you.
import PIL.Image
from PIL import Image
img1 = Image.open("image1.jpg")
img2 = Image.open("image2.jpg")
img3 = Image.open("image3.jpg")
img4 = Image.open("image4.jpg")
img5 = Image.open("image5.jpg")
img6 = Image.open("image6.jpg")
img7 = Image.open("image7.jpg")
img8 = Image.open("image8.jpg")
img9 = Image.open("image9.jpg")
img10 = Image.open("image10.jpg")
img11 = Image.open("image11.jpg")
img12 = Image.open("image12.jpg")
# ascii characters used to build the output text
#ASCII_CHARS = ["#", "#", "S", "%", "?", "*", "+", ";", ":", ",", "."]
ASCII_CHARS = [img1, img2, img3, img4, img5, img6, img8, img9, img10, img11, img12]
# resize image according to a new width
def resize_image(image, new_width=80):
width, height = image.size
ratio = height/width
new_height = int(new_width * ratio)
resized_image = image.resize((new_width, new_height))
return(resized_image)
# convert each pixel to greyscale
def grayify(image):
grayscale_image = image.convert("L")
return(grayscale_image)
# convert pixels to a string of ASCII characters
def pixels_to_ascii(image):
pixels = image.getdata()
characters = "".join([ASCII_CHARS[pixel//25] for pixel in pixels])
return(characters)
def main(new_width=80):
# attempt to open image from user-input
path = input("Enter path to image:\n")
try:
image = PIL.Image.open(path)
except:
print(path, " is not a valid pathname to an image")
return
# convert image to ASCII
new_image_data = pixels_to_ascii(grayify(resize_image(image)))
# format
pixel_count = len(new_image_data)
ascii_image = "\n".join([new_image_data[index:(index+new_width)] for index in range(0, pixel_count, new_width)])
# print result
print(ascii_image)
# save
#with Image.open("ascii_image.jpg") as f:
# f.write(ascii_image)
main()
as a project for a course, I'm developing an image coder/decoder using python, but it seems I got a little stuck and I would really apreciate getting some help
The error I'm getting is:
runfile('D:/Documentos/Python/Proyecto_Final/Main.py', wdir='D:/Documentos/Python/Proyecto_Final')
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\...\anaconda3\lib\tkinter\__init__.py", line 1705, in __call__
return self.func(*args)
File "D:\Documentos\Python\Proyecto_Final\Main.py", line 32, in decode64
imagen.write(base64.decodebytes(baset.encode()))
File "C:\...\anaconda3\lib\base64.py", line 546, in decodebytes
return binascii.a2b_base64(s)
binascii.Error: Invalid base64-encoded string: number of data characters (1) cannot be 1 more than a multiple of 4
My code is:
from tkinter import *
import os
import base64
def browseBtn():
filename = filedialog.askopenfilename()
texto.insert(0, filename)
def convbase64():
path = str(texto.get())
imagen = open(path, 'rb')
leeimg = imagen.read()
codigo64 = base64.encodebytes(leeimg)
texto2.insert("1.0", codigo64)
def decode64():
myFormats = [('JPEG / JFIF','*.jpg'),\
('Portable Network Graphics','*.png'),\
('Windows Bitmap','*.bmp'),('CompuServer GIF','*.gif'),]
baset = texto2.get(1.0)
filepath = filedialog.asksaveasfilename(filetypes=myFormats)
imagen = open(filepath, 'wb')
imagen.write(base64.decodebytes(baset.encode()))
imagen.close()
ventana = Tk()
ventana.title("Convertidor imagen a Base64")
ventana.geometry("800x480")
letrero = Label(ventana, text = "Imagen:")
texto = Entry(ventana, width = 100)
buscarImg = Button(ventana, text = "Elegir", command=browseBtn)
letrero2 = Label(ventana, text = "codigo base64:")
texto2 = Text(width = 75, height = 1)
btnconvertir = Button(ventana, text = "Codificar", command=convbase64)
btndecodificar = Button(ventana, text = "decodificar", command=decode64)
letrero.place(x = 32, y = 32)
letrero2.place(x = 16, y = 64)
texto.place(x = 114, y = 35)
texto2.place(x = 114, y = 69)
buscarImg.place(x = 724, y = 32)
btnconvertir.place(x = 724, y = 64)
btndecodificar.place (x = 724, y = 96)
ventana.mainloop()
I'm using anaconda's Spyder 3.7
When using Text.get to get more than one character, you need to give it an end position. You can use the special string "end" for this, but ignoring the last newline character that tkinter adds with "end-1c":
baset = texto2.get("1.0", "end-1c")
See this answer for more information
When I am processing a bunch of images, on one of them I get this error
File "/home/tensorflowpython/firstmodel/yololoss.py", line 153, in data_generator
image, box = get_random_data(annotation_lines[i], input_shape, random=True)
File "/home/tensorflowpython/firstmodel/yololoss.py", line 226, in get_random_data
image = image.resize((nw,nh), Image.BICUBIC)
File "/home/tensorflowpython/kenv/lib/python3.6/site-packages/PIL/Image.py", line 1858, in resize
self.load()
File "/home/tensorflowpython/kenv/lib/python3.6/site-packages/PIL/ImageFile.py", line 247, in load
"(%d bytes not processed)" % len(b)
OSError: image file is truncated (25 bytes not processed)
I have already tried the solution suggested here but it doesn't work
my code looks like this
from PIL import Image
def get_random_data(annotation_line, input_shape, random=True, max_boxes=20, jitter=.3, hue=.1, sat=1.5, val=1.5, proc_img=True):
Image.LOAD_TRUNCATED_IMAGES = True
line = annotation_line.split()
image = Image.open(line[0])
iw, ih = image.size
h, w = input_shape
box = np.array([np.array(list(map(int,box.split(',')))) for box in line[1:]])
try:
image.load()
except IOError:
pass # You can always log it to logger
if not random:
# resize image
scale = min(w/iw, h/ih)
nw = int(iw*scale)
nh = int(ih*scale)
dx = (w-nw)//2
dy = (h-nh)//2
image_data=0
if proc_img:
image = image.resize((nw,nh), Image.BICUBIC)
new_image = Image.new('RGB', (w,h), (128,128,128))
new_image.paste(image, (dx, dy))
image_data = np.array(new_image)/255.
# correct boxes
box_data = np.zeros((max_boxes,5))
if len(box)>0:
np.random.shuffle(box)
if len(box)>max_boxes: box = box[:max_boxes]
box[:, [0,2]] = box[:, [0,2]]*scale + dx
box[:, [1,3]] = box[:, [1,3]]*scale + dy
box_data[:len(box)] = box
return image_data, box_data
# resize image
new_ar = w/h * rand(1-jitter,1+jitter)/rand(1-jitter,1+jitter)
scale = rand(.25, 2)
if new_ar < 1:
nh = int(scale*h)
nw = int(nh*new_ar)
else:
nw = int(scale*w)
nh = int(nw/new_ar)
image = image.resize((nw,nh), Image.BICUBIC) #error occurs here
The difference between my error and the previous solution is, mine says OS error and the solution is for IO error
EDIT: I have figured out the image that is causing this error, it can be downloaded from this link
I tried the solution that you linked with the truncated image and it worked. You made a slight mistake when trying to apply this solution: you have to set ImageFile.LOAD_TRUNCATED_IMAGES=True, not Image.LOAD_TRUNCATED_IMAGES.
LOAD_TRUNCATED_IMAGES does not originally exist in Image module, so when you do Image.LOAD_TRUNCATED_IMAGES=True you set a new variable which is not used by the library.
So I think you juste have to do that:
from PIL import ImageFile, Image
ImageFile.LOAD_TRUNCATED_IMAGES = True
image = Image.open("00090.jpg")
# resize now doesn't fail
image.resize((h, w), Image.BICUBIC)
I'm doing a .png file to tfrecord.
def _bytes_feature(value):
"""Wrapper for inserting bytes features into Example proto."""
return tf.train.Feature(bytes_list=tf.train.BytesList(value=[value]))
convert to example file:
def _convert_to_example(filename, image_buffer, label, text, height, width):
example = tf.train.Example(features=tf.train.Features(feature={
'image/height': _int64_feature(height),
'image/width': _int64_feature(width),
........
'image/encoded': _bytes_feature(image_buffer)})) #Error
return example
decode_png file, not sure this part
def decode_png(image_data):
img_str = image_data.tostring()
reconstructed_img_1d = np.fromstring(img_str, dtype=np.uint8)
reconstructed_img = reconstructed_img_1d.reshape(image_data.shape)
return reconstructed_img
process_image file:
def _process_image(filename):
# Read the image file.
with open(filename, 'r') as f:
image_data = io.imread(f)
# Decode the RGB PNG.
image = decode_png(image_data)
# Check that image converted to RGB
assert len(image.shape) == 3
height = image.shape[0]
width = image.shape[1]
assert image.shape[2] == 3
return image_data, height, width
Main, process image files batch:
for i in files_in_shard:
filename = filenames[i]
label = labels[i]
text = texts[i]
image_buffer, height, width = _process_image(filename)
example = _convert_to_example(filename, image_buffer, label,
text, height, width)
writer.write(example.SerializeToString())
shard_counter += 1
counter += 1
But, there is a error that TypeError: array([[[223, 198, 219],
[215, 185, 209],
[207, 174, 201],
...,
[230 has type numpy.ndarray, but expected one of: bytes
How should I deal with this? Any help would be great.
Thank you
Ok I got it... logic pro
def decode_png(image_data):
img_str = image_data.tostring()
reconstructed_img_1d = np.fromstring(img_str, dtype=np.uint8)
reconstructed_img = reconstructed_img_1d.reshape(image_data.shape)
return img_str
def _process_image(filename):
# Read the image file.
with open(filename, 'r') as f:
image_data = io.imread(f)
# Decode the RGB PNG.
img_str = image_data.tostring()
height = image_data.shape[0]
width = image_data.shape[1]
return img_str, height, width
I apologize for newbie mistakes - I am a true Python newbie.
A little insight on the image at hand and why I'm parsing information:
The attached image is a UB-04 form (or CMS-1450) and it's a uniform billing form used by institutional providers for claim billing. Although it was developed by The Centers for Medicare and Medicaid (CMS), it has become the standard form used by all insurance carriers.
UB04 Example
I receive these forms as PDFs where each provider has filled information with regards to treatment they gave in order to receive payments by the government or private insurer. I was manually extracting information from these PDFs but built a process to make this faster. However, this process is not robust enough and I wish to improve it, if possible.
I've added a sample of this form with some text I randomly edited in.
#I need to clean up these imports -_-
import pytesseract
from PIL import Image as IMG
import PIL
import cv2
from wand.image import Image
import PythonMagick
import pandas as pd
import operator
import functools
import csv
from openpyxl import Workbook, load_workbook
import numpy as np
import math
from matplotlib import pyplot as plt
import os
import xlsxwriter
from random import randint
import glob
import datetime
# Choose PDF series to convert to images - parse the images page by page
pdfclaimtoconvert = "UB04 PDF"
with(Image(filename=pdfclaimtoconvert+".pdf",resolution=200)) as source:
images=source.sequence
pages=len(images)
for i in range(pages):
Image(images[i]).save(filename='Cropped Images/'+pdfclaimtoconvert+str(i)+'.tiff')
# Loop through all pages
for page in range(0,pages):
# Select page number to parse text from
pagenumber = str(page)
filetoworkon = 'Cropped Images/'+pdfclaimtoconvert+pagenumber+'.tiff'
# Read & Write image back as tiff
image = cv2.imread(filetoworkon)
cv2.imwrite("test.tiff",image)
# Convert Red Pixels to white (this helps eliminate noise for tesseract to work properly)
image_tiff = IMG.open('test.tiff')
# load the pixel info
width, height = image_tiff.size
for x in range(width):
for y in range(height):
r,g,b = image_tiff.getpixel((x,y))
if r > 130 and b < 240:
image_tiff.putpixel((x, y), (255,255,255))
image_tiff.save('test.tiff')
This upcoming section is my main hurtle right now - Ideally, rather than strictly specifying a segmentation, I would like to incept a process where I can identify each one of those borders (for example top left would be border space 1, border space next to it would be border space 2 etc) - I assume there may be hundreds on this document), and then I can run a script that will segment on those borders exactly and parse information as needed.
#Read Image and Crop relevant sections
img = cv2.imread('test.tiff')
crop_img = img[20:170, 20:530] # Address
cv2.imwrite("Cropped Images/test1.tiff", crop_img)
crop_img = img[200:240, 20:530] #patient name
cv2.imwrite("Cropped Images/test2.tiff", crop_img)
crop_img = img[260:310, 20:205] #birthdate
cv2.imwrite("Cropped Images/test3.tiff", crop_img)
crop_img = img[400:570, 20:860] #Payer Address
cv2.imwrite("Cropped Images/test4.tiff", crop_img)
crop_img = img[600:1340, 20:120] #Treatment Codes
cv2.imwrite("Cropped Images/test5.tiff", crop_img)
crop_img = img[600:1340, 121:620] #Treatment Descriptions
cv2.imwrite("Cropped Images/test6.tiff", crop_img)
crop_img = img[600:1340, 620:910] #HCPCS
cv2.imwrite("Cropped Images/test7.tiff", crop_img)
crop_img = img[600:1340, 910:1059] #Service Dates
cv2.imwrite("Cropped Images/test8.tiff", crop_img)
crop_img = img[600:1340, 1059:1220] #Service Units
cv2.imwrite("Cropped Images/test9.tiff", crop_img)
crop_img = img[600:1340, 1214:1365] #Service Charges
cv2.imwrite("Cropped Images/test10.tiff", crop_img)
crop_img = img[600:1340, 1355:1420] #Service Charges decimals
cv2.imwrite("Cropped Images/test11.tiff", crop_img)
crop_img = img[1400:1510,20:480] #Payer Name
cv2.imwrite("Cropped Images/test12.tiff", crop_img)
crop_img = img[20:75,1070:1580] #Patient Control No
cv2.imwrite("Cropped Images/test13.tiff", crop_img)
crop_img = img[75:105,1070:1400] #Med Rec
cv2.imwrite("Cropped Images/test14.tiff", crop_img)
crop_img = img[130:175,1015:1220] #Fed Tax No
cv2.imwrite("Cropped Images/test15.tiff", crop_img)
crop_img = img[135:175,1220:1510] #Statement from and To
cv2.imwrite("Cropped Images/test16.tiff", crop_img)
crop_img = img[1340:1372,900:1050] #Creation Date
cv2.imwrite("Cropped Images/test17.tiff", crop_img)
crop_img = img[1662:1700,630:1160] #Document Control No
cv2.imwrite("Cropped Images/test18.tiff", crop_img)
crop_img = img[1340:1372,130:280] #Pages #1
cv2.imwrite("Cropped Images/test19.tiff", crop_img)
crop_img = img[1340:1372,280:500] #Pages #2
cv2.imwrite("Cropped Images/test20.tiff", crop_img)
# Use Tesseract to Read text for each of the crops - input in a list
# Separate numerical exrtactions from mixed or string so that we can force tesseract to recognize them as digits
TextExtract = {}
numericals = [1, 2, 3, 4, 5, 6, 7, 8, 12, 13, 14, 15, 16, 17, 18]
nonnumericals = [9, 10, 11, 19, 20]
for i in numericals:
img = IMG.open(
'YOURPATH/Cropped Images/test' + str(i) + '.tiff')
img.load()
TextExtract["test{0}".format(i)] = pytesseract.image_to_string(img, config='-psm 6')
for i in nonnumericals:
img = IMG.open(
'YOURPATH/Cropped Images/test' + str(i) + '.tiff')
img.load()
TextExtract["test{0}".format(i)] = pytesseract.image_to_string(img,
config='-c tessedit_char_whitelist=0123456789 -psm 6')
# Split each item in dictionary by page break
ParsedText = {}
for i in range(1, 21):
ParsedText["test{0}".format(i)] = TextExtract['test' + str(i)].split('\n')
# Delete empty list items
for x in range(1, 21):
ParsedText['test' + str(x)] = [i for i in ParsedText['test' + str(x)] if i != '']
# Collapse lists into single values
CollapsedLists = {}
collapsablelist=(1,2,3,4,12,13,14,15,16,17,18,19,20)
for i in range(1,21):
if i in collapsablelist:
CollapsedLists["test{0}".format(i)] = ' '.join(ParsedText['test'+str(i)])
else:
CollapsedLists["test{0}".format(i)] = ParsedText['test'+str(i)]
# Extraction list
extractionlist = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20)
# Create empty Pandas Dataframe
extractionframe = pd.DataFrame(columns=['test1', 'test2', 'test3', 'test4', 'test5', 'test6', 'test7', 'test8'
, 'test9', 'test10', 'test11', 'test12', 'test13', 'test14', 'test15', 'test16'
, 'test17', 'test18', 'test19', 'test20'
])
# Populate dataframe
for x in extractionlist:
if isinstance(CollapsedLists['test' + str(x)], list) is False:
try:
extractionframe.loc[1, 'test' + str(x)] = CollapsedLists['test' + str(x)]
except:
pass
else:
for i in range(len(CollapsedLists['test' + str(x)])):
extractionframe.loc[i + 1, 'test' + str(x)] = CollapsedLists['test' + str(x)][i]
# Populate source
extractionframe.loc[1, 'source'] = pdfclaimtoconvert + '_page_' + pagenumber
# Fill NaN values forward
extractionframe = extractionframe.fillna(method='ffill')
#Convert to excel formula in order to preserve any leading zeroes
extractionframe = extractionframe.applymap(str)
extractionframe2 = '="'+extractionframe+'"'
# Export to excel
with open('Claim Data Extractions.csv', 'a') as f:
extractionframe2.to_csv(f, header=False, index=False)
You need some sort of contour analysis. Most of the hard work is encapsulated in OpenCV and you have a terrific example to inspire you here.