Pytesser inaccurate - python

Simple question. When I run this image through pytesser, i get $+s. How can I fix that?
EDIT
So... my code generates images similar to the image linked above, just with different numbers, and is supposed to solve the simple math problem, which is obviously impossible if all I can get out of the picture is $+s
Here's the code I'm currently using:
from pytesser import *
time.sleep(2)
i = 0
operator = "+"
while i < 100:
time.sleep(.1);
img = ImageGrab.grab((349, 197, 349 + 452, 197 + 180))
equation = image_to_string(img)
Then I'm going to go on to parse equation... as soon as I get pytesser working.

Try my little function. I'm running tesseract from the svn repo, so my results might be more accurate.
I'm on Linux, so on Windows, I'd imagine that you'll have to replace tesseract with tesseract.exe to make it work.
import tempfile, subprocess
def ocr(image):
tempFile = tempfile.NamedTemporaryFile(delete = False)
process = subprocess.Popen(['tesseract', image, tempFile.name], stdout = subprocess.PIPE, stdin = subprocess.PIPE, stderr = subprocess.STDOUT)
process.communicate()
handle = open(tempFile.name + '.txt', 'r').read()
return handle
And a sample Python session:
>>> import tempfile, subprocess
>>> def ocr(image):
... tempFile = tempfile.NamedTemporaryFile(delete = False)
... process = subprocess.Popen(['tesseract', image, tempFile.name], stdout = subprocess.PIPE, stdin = subprocess.PIPE, stderr = subprocess.STDOUT)
... process.communicate()
... handle = open(tempFile.name + '.txt', 'r').read()
... return handle
...
>>> print ocr('326_fail.jpg')
0+1

if you're in linux, use gocr is more accurate. you can use it through
os.system("/usr/bin/gocr %s") % (sample_image)
and use readlines from stdout for manipulating output result to everything what you want (i.e creating output from gocr for specific variable).

Related

Is there a way to check if script is running from subprocess?

Let's say I have a python script which reads all the images in a folder and resizes them. The script works all by his own, it takes in two arguments - the input folder and an output folder.
To have a visual response of the progress I'm using a progressbar which is printed out to the console/terminal.
resize.py:
import argparse
import fnmatch
import os
import PIL
from PIL import Image
from progress.bar import Bar
parser = argparse.ArgumentParser(description='Photo resizer.')
parser.add_argument('input_folder', nargs='?', default='', help="Input folder")
parser.add_argument('export_folder', nargs='?', default='', help="Output folder")
args = parser.parse_args()
if args.input_folder:
input_folder = args.input_folder
if args.export_folder:
export_resized_folder = args.export_folder
NEW_SIZE = 2000
inputFiles = []
for root, dirnames, filenames in os.walk(input_folder):
for filename in fnmatch.filter(filenames, '*.jpg'):
inputFiles.append(os.path.join(root, filename))
bar = Bar("Processing photos", max=len(inputFiles), check_tty=False)
for photo in inputFiles:
filename = os.path.basename(photo)
im = Image.open(photo)
im_width, im_height = im.size
if im_width > im_height:
new_width = NEW_SIZE
new_height = int(NEW_SIZE * im_height / im_width)
else:
new_height = NEW_SIZE
new_width = int(NEW_SIZE * im_width / im_height)
new_size = (new_width, new_height)
im_resized = im.resize(new_size, resample=PIL.Image.Resampling.LANCZOS)
im_resized.save(os.path.join(export_resized_folder, filename), quality=70)
bar.next()
bar.finish()
Now I have an another script (main_gui.py) which does some batch processing and one of the jobs is to resize the images. This script provides a simple GUI. When it comes to resizing the images, I use subprocess Popen to execute the script and pass in the input and output folders as args.
So in main_gui.py I start the subprocess:
script_path = "resize.py"
process = subprocess.Popen(["python", script_path, INPUT_FOLDER, OUTPUT_FOLDER], universal_newlines=True, stdout=subprocess.PIPE)
Now I'd like to see the progress in the GUI also. I don't know if I'm doing it correctly (It is a high probability that not, this is just the first thing that came to my mind)...
So in resize.py along with the progressbar I print out information about my progress and then read it in the main_gui.py and based on that information I update a tkinter progressbar.
In resize.py:
bar = Bar("Processing photos", max=len(inputFiles), check_tty=False)
print("**TOTAL** " + str(len(inputFiles)))
...
progressCounter = 1
for photo in inputFiles:
...
bar.next()
print("**PROGRESS** " + str(progressCounter))
progressCounter += 1
...
I read these values in main_gui.py
process = subprocess.Popen(["python", script_path], universal_newlines=True, stdout=subprocess.PIPE)
while process.poll() is None:
data = process.stdout.readline().strip()
print(data)
if "**TOTAL** " in data:
total = int(data.replace("**TOTAL** ", ""))
progressbarWidget['maximum'] = total
if "**PROGRESS** " in data and self.GUI:
progressCounter = int(data.replace("**PROGRESS** ", ""))
progressbarWidget['value'] = progressCounter
progressbarWidget.update_idletasks()
And at this point I'd like in my resize.py check if it is run by itself or by the subprocess, so I don't have the unnecessary print statements.
I tried pass in an env value as Charles suggested in the comments, but couldn't get it done
Trying to detect your parent process is an unnecessary amount of magic for this use case. Making it explicit with an optional argument will let others writing their own GUIs (potentially in non-Python languages) get the machine-readable status output without needing to try to fool the detection.
parser = argparse.ArgumentParser(description='Photo resizer.')
parser.add_argument('--progress', choices=('none', 'human', 'machine-readable'), default='none',
help="Should a progress bar be written to stderr in a human-readable form, to stdout in a machine-readable form, or not at all?")
parser.add_argument('input_folder', nargs='?', default='', help="Input folder")
parser.add_argument('export_folder', nargs='?', default='', help="Output folder")
args = parser.parse_args()
...and then later...
if args.progress == 'machine-readable':
pass # TODO: Write your progress messages for the programmatic consumer to stdout here
elif args.progress == 'human':
pass # TODO: Write your progress bar for a human reader to stderr here
while on the GUI side, adding --progress=human to the argument list:
process = subprocess.Popen([sys.executable, script_path, '--progress=human'],
universal_newlines=True, stdout=subprocess.PIPE)

Python stdout and stdout.buffer capture

Hey i want to prevent any stdouts from anywhere and capture it in a variable.
Now the problem:
I have two methods to print something in stdout
Method 1:
print("Normal Print")
Method 2:
fds: List[BinaryIO] = [sys.stdin.buffer, sys.stdout.buffer, sys.stderr.buffer]
fds[1].write(b"%d\n" % a)
fds[1].flush()
Now i tried something like this
from io import BufferedWriter, BytesIO, StringIO
mystdout = StringIO()
mystdout.buffer = BufferedWriter(raw=BytesIO())
sys.stdout = mystdout
But with this i get no output at all.
How is the best way to archiev this?
What do you mean that you get no output at all? It's in variable:
mystdout = StringIO()
mystdout.buffer = BufferedRandom(raw=BytesIO()) # You can read from BufferedRandom
sys.stdout = mystdout
sys.stdout.buffer.write(b"BUFFER")
print("PRINT")
sys.stdout = sys.__stdout__ # Restore original stdout
print(mystdout.getvalue()) # PRINT
mystdout.buffer.seek(0)
print(mystdout.buffer.read()) b"BUFFER"

OpenCV read video files with multiple streams/tracks

I have a video file that contains multiple streams as shown below using VLC media player:
Video Information
When I try to read it using Python + OpenCV using the following code:
vidObj = cv2.VideoCapture("video.avi")
ret, frame = vidObj.read()
I can only read the first track of the video. How can I read all the video tracks at the same time?
As far as I could tell, OpenCV does not allow choosing video stream, so this is not possible. However, you can do it rather easily with ffmpeg command line utilities:
import numpy as np
import json
import subprocess
def videoInfo(filename):
proc = subprocess.run([
*"ffprobe -v quiet -print_format json -show_format -show_streams".split(),
filename
], capture_output=True)
proc.check_returncode()
return json.loads(proc.stdout)
def readVideo(filename):
cmd = ["ffmpeg", "-i", filename]
streams = 0
for stream in videoInfo(filename)["streams"]:
index = stream["index"]
if stream["codec_type"] == "video":
width = stream["width"]
height = stream["height"]
cmd += "-map", f"0:{index}"
streams = streams + 1
cmd += "-f", "rawvideo", "-pix_fmt", "rgb24", "-"
shape = np.array([streams, height, width, 3])
with subprocess.Popen(cmd, stdout=subprocess.PIPE) as proc:
while True:
data = proc.stdout.read(shape.prod()) # One byte per each element
if not data:
return
yield np.frombuffer(data, dtype=np.uint8).reshape(shape)
Note that the code reads all video streams and assumes that each has the same resolution. It lacks proper error handling but got the job done in my scientific project.
For example, reading stereoscopic stream:
import matplotlib.pyplot as plt
for left, right in readVideo("testvideo.mkv"):
plt.imshow(left)
plt.show()
plt.imshow(right)
plt.show()

How to generate HTML color diff from git using python

So I figured out creating HTML git diff i can embed in email but don't know why is it all being spit in one line ?
here is how I did it!!
import sys
import subprocess
import os
from ansi2html.converter import Ansi2HTMLConverter
ansiText = os.path.expanduser('~/Desktop/colorDiff')
pr = subprocess.Popen( "git diff HEAD^ HEAD --color > "+ansiText , cwd = os.getcwd() , shell = True, stdout = subprocess.PIPE, stderr = subprocess.PIPE )
(out, error) = pr.communicate()
conv = Ansi2HTMLConverter()
ansi = ''
with open(ansiText, 'r+') as fh:
fh.readline()
for line in fh:
ansi += ''.join(line.split())
html = conv.convert(ansi)
with open("%s.html" % ansiText, 'w+') as wf:
wf.write(html)
os.remove(ansiText)
print str(error).capitalize()
maybe its too late to be awake...
figured out myself
import sys
import subprocess
import os
from ansi2html.converter import Ansi2HTMLConverter
ansiText = os.path.expanduser('~/Desktop/colorDiff')
proc = subprocess.Popen('git diff HEAD^ HEAD --color', shell=True, stdout=subprocess.PIPE, stderr = subprocess.PIPE )
diffData = proc.stdout.read()
conv = Ansi2HTMLConverter()
html = conv.convert(diffData)
with open("%s.html" % ansiText, 'w') as wf:
wf.write(html)

Creating a set from a variable instead of a file

I have a piece of code to read two files, convert them to sets, and then subtract one set from the other. I would like to use a string variable (installedPackages) for "a" instead of a file. I would also like to write to a variable for "c".
a = open("/home/user/packages1.txt")
b = open("/home/user/packages.txt")
c = open("/home/user/unique.txt", "w")
for line in set(a) - set(b):
c.write(line)
a.close()
b.close()
c.close()
I have tried the following and it does not work:
for line in set(installedPackages) - set(b):
I have tried to use StringIO, but I think I am using it improperly.
Here, finally, is how I have created installedPackages:
stdout, stderr = p.communicate()
installedPackages = re.sub('\n$', '', re.sub('install$', '', re.sub('\t', '', stdout), 0,re.MULTILINE))
Sample of packages.txt:
humanity-icon-theme
hunspell-en-us
hwdata
hyphen-en-us
ibus
ibus-gtk
ibus-gtk3
ibus-pinyin
ibus-pinyin-db-android
ibus-table
If you want to write to a string buffer file-like use StringIO
>>> from StringIO import StringIO
>>> installed_packages = StringIO()
>>> installed_packages.write('test')
>>> installed_packages.getvalue()
'test'
Something like the following?
Edit: after several iterations:
from subprocess import Popen, PIPE
DEBUG = True
if DEBUG:
def log(msg, data):
print(msg)
print(repr(data))
else:
def log(msg, data):
pass
def setFromFile(fname):
with open(fname) as inf:
return set(ln.strip() for ln in inf)
def setFromString(s):
return set(ln.strip() for ln in s.split("\n"))
def main():
# get list of installed packages
p = Popen(['dpkg', '--get-selections'], stdout=PIPE, stderr=PIPE)
stdout, stderr = p.communicate()
installed_packages = setFromString(stdout)
# get list of expected packages
known_packages = setFromFile('/home/john/packages.txt')
# calculate the difference
unknown_packages = installed_packages - known_packages
unknown_packages_string = "\n".join(unknown_packages)
log("Installed packages:", installed_packages)
log("Known packages:", known_packages)
log("Unknown packages:", unknown_packages)
if __name__=="__main__":
main()
The set data type takes an iterable as a parameter, therefore if installedPackages a string with multiple items you need to split it by the delimiter. For example, the following code would split the string by all commas:
for line in set(installedPackages.split(',')) - set(b):
c.write(line)

Categories