I have a json file which contain polygons of filled circles. How can i implement this json file to the below code to get masks?
def polygons_to_mask_array_labelme(polygons, width : int = 300, height : int = 300) -> np.ndarray:
'''
This function takes a list of lists that contains polygon masks for each building. Example;
[[x11,y11,x12,y12,...],...,[xn1,yn1,xn2,yn2,...]]
The return of this function is an array of size width x height which contains a binary mask
as defined by the list of polygons
Example usage:
import json
with open(json_names[0], encoding = 'utf-8') as f:
data = json.load(f)
plt.imshow(polygons_to_mask_array(data['shapes'], 898, 559))
'''
img = Image.new('L', (width, height), 0)
for polygon in polygons:
nested_lst_of_tuples = [tuple(l) for l in polygon['points']]
try:
ImageDraw.Draw(img).polygon(nested_lst_of_tuples, outline=1, fill=1)
except:
print(nested_lst_of_tuples)
mask = np.array(img)
return mask
and the json file is:
name is f90.json, which shows
{"polygons": ["220.5,43.0 224.3625,42.38749999999999 227.85,40.61250000000001 230.6125,37.849999999999994 232.3875,34.36250000000001 233.0,30.5 232.3875,26.63749999999999 230.6125,23.150000000000006 227.85,20.38749999999999 224.3625,18.61250000000001 220.5,18.0 216.6375,18.61250000000001 213.15,20.38749999999999 210.3875,23.150000000000006 208.6125,26.63749999999999 208.0,30.5 208.6125,34.36250000000001 210.3875,37.849999999999994 213.15,40.61250000000001 216.6375,42.38749999999999", "351.5,116.0 355.3625,115.38749999999999 358.85,113.61250000000001 361.6125,110.85 363.3875,107.36250000000001 364.0,103.5 363.3875,99.63749999999999 361.6125,96.15 358.85,93.38749999999999 355.3625,91.61250000000001 351.5,91.0 347.6375,91.61250000000001 344.15,93.38749999999999 341.3875,96.15 339.6125,99.63749999999999 339.0,103.5 339.6125,107.36250000000001 341.3875,110.85 344.15,113.61250000000001 347.6375,115.38749999999999", "314.5,368.0 318.3625,367.3875 321.85,365.6125 324.6125,362.85 326.3875,359.3625 327.0,355.5 326.3875,351.6375 324.6125,348.15 321.85,345.3875 318.3625,343.6125 314.5,343.0 310.6375,343.6125 307.15,345.3875 304.3875,348.15 302.6125,351.6375 302.0,355.5 302.6125,359.3625 304.3875,362.85 307.15,365.6125 310.6375,367.3875", "475.5,353.0 479.3625,352.3875 482.85,350.6125 485.6125,347.85 487.3875,344.3625 488.0,340.5 487.3875,336.6375 485.6125,333.15 482.85,330.3875 479.3625,328.6125 475.5,328.0 471.6375,328.6125 468.15,330.3875 465.3875,333.15 463.6125,336.6375 463.0,340.5 463.6125,344.3625 465.3875,347.85 468.15,350.6125 471.6375,352.3875"]}
Related
Getting error: line 50, in
faceA = preprocess_face(rgbA[boxesA[0][1]:boxesA[0][3], boxesA[0][0]:boxesA[0][2]])
TypeError: only integer scalar arrays can be converted to a scalar index
import os
import argparse
import cv2
from deepface import DeepFace
import numpy as np
# construct the argument parse and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-f", "--first", required=True,
help="first input image")
ap.add_argument("-d", "--directory", required=True,
help="directory of images to compare")
args = vars(ap.parse_args())
# load the first input image
imageA = cv2.imread(args["first"])
rgbA = cv2.cvtColor(imageA, cv2.COLOR_BGR2RGB)
# detect the face in the first image
boxesA = DeepFace.detectFace(rgbA)
# make sure there is a face in the first image
if len(boxesA) == 0:
print("No face detected in the first image")
exit()
def preprocess_face(face, size=(96, 96)):
# extract the face ROI and resize it to the desired size
face = cv2.resize(face, size)
# compute the scaling factor for the images
factor_0 = size[0] / face.shape[0]
factor_1 = size[1] / face.shape[1]
factor = np.min([factor_0, factor_1])
# stretch the face ROI to the desired size
face = cv2.resize(face, None, fx=factor, fy=factor)
# convert the face ROI to grayscale
gray = cv2.cvtColor(face, cv2.COLOR_BGR2GRAY)
# normalize the grayscale image
gray = gray / 255.0
# return the preprocessed face
return [gray]
boxesA = boxesA.astype(int)
# extract the face encoding for the first image
faceA = preprocess_face(rgbA[boxesA[0][1]:boxesA[0][3], boxesA[0][0]:boxesA[0][2]])
encodingA = DeepFace.detectFace(faceA, boxesA)[0]
# initialize a dictionary to store the image names and scores
scores = {}
# loop over the images in the directory
for image_name in os.listdir(args["directory"]):
# load the image
imageB = cv2.imread(os.path.join(args["directory"], image_name))
rgbB = cv2.cvtColor(imageB, cv2.COLOR_BGR2RGB)
# detect the face in the image
boxesB = DeepFace.detectFace(rgbB, enforce_detection=False)
# make sure there is a face in the image
if len(boxesB) == 0:
continue
boxesB = boxesB.astype(int)
# extract the face encoding for the image
facesB = []
for i in range(len(boxesB)):
faceB = preprocess_face(rgbB[boxesB[i][1]:boxesB[i][3], boxesB[i][0]:boxesB[i][2]])
facesB.extend(faceB)
encodingB = DeepFace.detectFace(facesB, boxesB)[0]
# compare the face encodings
score = DeepFace.verifyFace(encodingA, encodingB)
similarity_percentage = score * 100
# store the image name and score in the dictionary
scores[image_name] = score
# sort the scores in descending order
sorted_scores = sorted(scores.items(), key=lambda x: x[1], reverse=True)
# display the top 10 scores
for i in range(10):
image_name, score = sorted_scores[i]
print("{}: {}".format(image_name, score))
Usage of the script is: python Image_Comparison_Deepface.py -f C:/folder/image.png -d C:/testpics
Script was created with ChatGPT.
I am working with the pykitti package for visualizing the KITTI data set in python. It's having trouble locating the calibration files needed. It looks in a specified directory for these calibration files. I specified the directory in which it should look for these files. However, it still gives me an error:
FileNotFoundError: [Errno 2] No such file or directory: '/home/spb5151/Downloads/KITTI_Data/2011_09_26/calib_imu_to_velo.txt'
It says that it's getting stuck on the open(filepath, 'r') line in my code.However, I have confirmed that this file is located in this directory. I'm using Pycharm as my IDE on linux. I'm new to python and linux so is there anything as far as syntax that I might be missing?
import sys
sys.path.insert(0, '/home/spb5151/Documents/pykitti-master')
import pykitti
basedir = '/home/spb5151/Downloads/KITTI_Data'
date = '2011_09_26'
drive = '0019'
# The 'frames' argument is optional - default: None, which loads the whole dataset.
# Calibration and timestamp data are read automatically.
# Other sensor data (cameras, IMU, Velodyne) are available via properties
# that create generators when accessed.
data = pykitti.raw(basedir, date, drive, frames=range(0, 50, 5))
# dataset.calib: Calibration data are accessible as a named tuple
# dataset.timestamps: Timestamps are parsed into a list of datetime objects
# dataset.oxts: Returns a generator that loads OXTS packets as named tuples
# dataset.camN: Returns a generator that loads individual images from camera N
# dataset.gray: Returns a generator that loads monochrome stereo pairs (cam0, cam1)
# dataset.rgb: Returns a generator that loads RGB stereo pairs (cam2, cam3)
# dataset.velo: Returns a generator that loads velodyne scans as [x,y,z,reflectance]
point_velo = np.array([0,0,0,1])
point_cam0 = data.calib.T_cam0_velo.dot(point_velo)
point_imu = np.array([0,0,0,1])
point_w = [o.T_w_imu.dot(point_imu) for o in data.oxts]
for cam0_image in data.cam0:
pass
rgb_iterator = data.rgb # Assign the generator so it doesn't
cam2_image, cam3_image = next(rgb_iterator)
And here is the raw.py file which is included in the pykitti package
"""Provides 'raw', which loads and parses raw KITTI data."""
import datetime as dt
import glob
import os
from collections import namedtuple
import numpy as np
import pykitti.utils as utils
__author__ = "Lee Clement"
__email__ = "lee.clement#robotics.utias.utoronto.ca"
class raw:
"""Load and parse raw data into a usable format."""
def __init__(self, base_path, date, drive, **kwargs):
"""Set the path and pre-load calibration data and timestamps."""
self.drive = date + '_drive_' + drive + '_sync'
self.calib_path = os.path.join(base_path, date)
self.data_path = os.path.join(base_path, date, self.drive)
self.frames = kwargs.get('frames', None)
# Setting imformat='cv2' will convert the images to uint8 and BGR for
# easy use with OpenCV.
self.imformat = kwargs.get('imformat', None)
# Pre-load data that isn't returned as a generator
self._load_calib()
self._load_timestamps()
def __len__(self):
"""Return the number of frames loaded."""
return len(self.timestamps)
#property
def oxts(self):
"""Generator to read OXTS data from file."""
# Find all the data files
oxts_path = os.path.join(self.data_path, 'oxts', 'data', '*.txt')
oxts_files = sorted(glob.glob(oxts_path))
# Subselect the chosen range of frames, if any
if self.frames is not None:
oxts_files = [oxts_files[i] for i in self.frames]
# Return a generator yielding OXTS packets and poses
return utils.get_oxts_packets_and_poses(oxts_files)
#property
def cam0(self):
"""Generator to read image files for cam0 (monochrome left)."""
impath = os.path.join(self.data_path, 'image_00', 'data', '*.png')
imfiles = sorted(glob.glob(impath))
# Subselect the chosen range of frames, if any
if self.frames is not None:
imfiles = [imfiles[i] for i in self.frames]
# Return a generator yielding the images
return utils.get_images(imfiles, self.imformat)
#property
def cam1(self):
"""Generator to read image files for cam1 (monochrome right)."""
impath = os.path.join(self.data_path, 'image_01', 'data', '*.png')
imfiles = sorted(glob.glob(impath))
# Subselect the chosen range of frames, if any
if self.frames is not None:
imfiles = [imfiles[i] for i in self.frames]
# Return a generator yielding the images
return utils.get_images(imfiles, self.imformat)
#property
def cam2(self):
"""Generator to read image files for cam2 (RGB left)."""
impath = os.path.join(self.data_path, 'image_02', 'data', '*.png')
imfiles = sorted(glob.glob(impath))
# Subselect the chosen range of frames, if any
if self.frames is not None:
imfiles = [imfiles[i] for i in self.frames]
# Return a generator yielding the images
return utils.get_images(imfiles, self.imformat)
#property
def cam3(self):
"""Generator to read image files for cam0 (RGB right)."""
impath = os.path.join(self.data_path, 'image_03', 'data', '*.png')
imfiles = sorted(glob.glob(impath))
# Subselect the chosen range of frames, if any
if self.frames is not None:
imfiles = [imfiles[i] for i in self.frames]
# Return a generator yielding the images
return utils.get_images(imfiles, self.imformat)
#property
def gray(self):
"""Generator to read monochrome stereo pairs from file.
"""
return zip(self.cam0, self.cam1)
#property
def rgb(self):
"""Generator to read RGB stereo pairs from file.
"""
return zip(self.cam2, self.cam3)
#property
def velo(self):
"""Generator to read velodyne [x,y,z,reflectance] scan data from binary files."""
# Find all the Velodyne files
velo_path = os.path.join(
self.data_path, 'velodyne_points', 'data', '*.bin')
velo_files = sorted(glob.glob(velo_path))
# Subselect the chosen range of frames, if any
if self.frames is not None:
velo_files = [velo_files[i] for i in self.frames]
# Return a generator yielding Velodyne scans.
# Each scan is a Nx4 array of [x,y,z,reflectance]
return utils.get_velo_scans(velo_files)
def _load_calib_rigid(self, filename):
"""Read a rigid transform calibration file as a numpy.array."""
filepath = os.path.join(self.calib_path, filename)
data = utils.read_calib_file(filepath)
return utils.transform_from_rot_trans(data['R'], data['T'])
def _load_calib_cam_to_cam(self, velo_to_cam_file, cam_to_cam_file):
# We'll return the camera calibration as a dictionary
data = {}
# Load the rigid transformation from velodyne coordinates
# to unrectified cam0 coordinates
T_cam0unrect_velo = self._load_calib_rigid(velo_to_cam_file)
# Load and parse the cam-to-cam calibration data
cam_to_cam_filepath = os.path.join(self.calib_path, cam_to_cam_file)
filedata = utils.read_calib_file(cam_to_cam_filepath)
# Create 3x4 projection matrices
P_rect_00 = np.reshape(filedata['P_rect_00'], (3, 4))
P_rect_10 = np.reshape(filedata['P_rect_01'], (3, 4))
P_rect_20 = np.reshape(filedata['P_rect_02'], (3, 4))
P_rect_30 = np.reshape(filedata['P_rect_03'], (3, 4))
data['P_rect_00'] = P_rect_00
data['P_rect_10'] = P_rect_10
data['P_rect_20'] = P_rect_20
data['P_rect_30'] = P_rect_30
# Create 4x4 matrices from the rectifying rotation matrices
R_rect_00 = np.eye(4)
R_rect_00[0:3, 0:3] = np.reshape(filedata['R_rect_00'], (3, 3))
R_rect_10 = np.eye(4)
R_rect_10[0:3, 0:3] = np.reshape(filedata['R_rect_01'], (3, 3))
R_rect_20 = np.eye(4)
R_rect_20[0:3, 0:3] = np.reshape(filedata['R_rect_02'], (3, 3))
R_rect_30 = np.eye(4)
R_rect_30[0:3, 0:3] = np.reshape(filedata['R_rect_03'], (3, 3))
data['R_rect_00'] = R_rect_00
data['R_rect_10'] = R_rect_10
data['R_rect_20'] = R_rect_20
data['R_rect_30'] = R_rect_30
# Compute the rectified extrinsics from cam0 to camN
T0 = np.eye(4)
T0[0, 3] = P_rect_00[0, 3] / P_rect_00[0, 0]
T1 = np.eye(4)
T1[0, 3] = P_rect_10[0, 3] / P_rect_10[0, 0]
T2 = np.eye(4)
T2[0, 3] = P_rect_20[0, 3] / P_rect_20[0, 0]
T3 = np.eye(4)
T3[0, 3] = P_rect_30[0, 3] / P_rect_30[0, 0]
# Compute the velodyne to rectified camera coordinate transforms
data['T_cam0_velo'] = T0.dot(R_rect_00.dot(T_cam0unrect_velo))
data['T_cam1_velo'] = T1.dot(R_rect_00.dot(T_cam0unrect_velo))
data['T_cam2_velo'] = T2.dot(R_rect_00.dot(T_cam0unrect_velo))
data['T_cam3_velo'] = T3.dot(R_rect_00.dot(T_cam0unrect_velo))
# Compute the camera intrinsics
data['K_cam0'] = P_rect_00[0:3, 0:3]
data['K_cam1'] = P_rect_10[0:3, 0:3]
data['K_cam2'] = P_rect_20[0:3, 0:3]
data['K_cam3'] = P_rect_30[0:3, 0:3]
# Compute the stereo baselines in meters by projecting the origin of
# each camera frame into the velodyne frame and computing the distances
# between them
p_cam = np.array([0, 0, 0, 1])
p_velo0 = np.linalg.inv(data['T_cam0_velo']).dot(p_cam)
p_velo1 = np.linalg.inv(data['T_cam1_velo']).dot(p_cam)
p_velo2 = np.linalg.inv(data['T_cam2_velo']).dot(p_cam)
p_velo3 = np.linalg.inv(data['T_cam3_velo']).dot(p_cam)
data['b_gray'] = np.linalg.norm(p_velo1 - p_velo0) # gray baseline
data['b_rgb'] = np.linalg.norm(p_velo3 - p_velo2) # rgb baseline
return data
def _load_calib(self):
"""Load and compute intrinsic and extrinsic calibration parameters."""
# We'll build the calibration parameters as a dictionary, then
# convert it to a namedtuple to prevent it from being modified later
data = {}
# Load the rigid transformation from velodyne to IMU
data['T_velo_imu'] = self._load_calib_rigid('calib_imu_to_velo.txt')
# Load the camera intrinsics and extrinsics
data.update(self._load_calib_cam_to_cam(
'calib_velo_to_cam.txt', 'calib_cam_to_cam.txt'))
# Pre-compute the IMU to rectified camera coordinate transforms
data['T_cam0_imu'] = data['T_cam0_velo'].dot(data['T_velo_imu'])
data['T_cam1_imu'] = data['T_cam1_velo'].dot(data['T_velo_imu'])
data['T_cam2_imu'] = data['T_cam2_velo'].dot(data['T_velo_imu'])
data['T_cam3_imu'] = data['T_cam3_velo'].dot(data['T_velo_imu'])
self.calib = namedtuple('CalibData', data.keys())(*data.values())
def _load_timestamps(self):
"""Load timestamps from file."""
timestamp_file = os.path.join(
self.data_path, 'oxts', 'timestamps.txt')
# Read and parse the timestamps
self.timestamps = []
with open(timestamp_file, 'r') as f:
for line in f.readlines():
# NB: datetime only supports microseconds, but KITTI timestamps
# give nanoseconds, so need to truncate last 4 characters to
# get rid of \n (counts as 1) and extra 3 digits
t = dt.datetime.strptime(line[:-4], '%Y-%m-%d %H:%M:%S.%f')
self.timestamps.append(t)
# Subselect the chosen range of frames, if any
if self.frames is not None:
self.timestamps = [self.timestamps[i] for i in self.frames]
Aha, for some reason they seemed to have hardcoded this part so that it doesn't consider your data path. Here's the culprit:
data['T_velo_imu'] = self._load_calib_rigid('calib_imu_to_velo.txt')
Search for this line in your raw.py file and replace the file with data_path + file to make sure it goes to the right path.
I use Tesseract and python to read digits (from a energy meter).
Everything works well except for the number "1".
Tesseract can not read the "1" Digit.
This is the picture I send to tesseract :
And tesseract reads "0000027 ".
How can I tell Tesseract that the vertical rod is a "1" ?
This is my tesseract initialisation :
import tesseract
TESSERACT_LIBRARY_PATH = "C:\\Program Files (x86)\\Tesseract-OCR"
LANGUAGE = "eng"
CHARACTERS = "0123456789"
FALSE = "0"
TRUE = "1"
def init_ocr():
"""
.. py:function:: init_ocr()
Utilize the Tesseract-OCR library to create an tesseract_ocr that
predicts the numbers to be read off of the meter.
:return: tesseract_ocr Tesseracts OCR API.
:rtype: Class
"""
# Initialize the tesseract_ocr with the english language package.
tesseract_ocr = tesseract.TessBaseAPI()
tesseract_ocr.Init(TESSERACT_LIBRARY_PATH, LANGUAGE,
tesseract.OEM_DEFAULT)
# Limit the characters being seached for to numerics.
tesseract_ocr.SetVariable("tessedit_char_whitelist", CHARACTERS)
# Set the tesseract_ocr to predict for only one character.
tesseract_ocr.SetPageSegMode(tesseract.PSM_AUTO)
# Tesseract's Directed Acyclic Graph.
# Not necessary for number recognition.
tesseract_ocr.SetVariable("load_system_dawg", FALSE)
tesseract_ocr.SetVariable("load_freq_dawg", FALSE)
tesseract_ocr.SetVariable("load_number_dawg", TRUE)
tesseract_ocr.SetVariable("classify_enable_learning", FALSE)
tesseract_ocr.SetVariable("classify_enable_adaptive_matcher", FALSE)
return tesseract_ocr
Slightly irrelevant answer, though may serve your original goal.
I had similar problem with tesseract and I had very strict performance requirements as well. I found this simple solution on SO and crafted simple recogniser with OpenCV.
It boils down to finding bounding rectangles (from edges) on the very clear image that you have and then trying to match found objects versus templates. I believe the solution in your case will be both simple and precise though will require slightly more code than you have now.
I will follow this question, since it will be nice to have working solution with tesseract.
I have a limited time, but it seems to be a working solution:
import os
import cv2
import numpy
KNN_SQUARE_SIDE = 50 # Square 50 x 50 px.
def resize(cv_image, factor):
new_size = tuple(map(lambda x: x * factor, cv_image.shape[::-1]))
return cv2.resize(cv_image, new_size)
def crop(cv_image, box):
x0, y0, x1, y1 = box
return cv_image[y0:y1, x0:x1]
def draw_box(cv_image, box):
x0, y0, x1, y1 = box
cv2.rectangle(cv_image, (x0, y0), (x1, y1), (0, 0, 255), 2)
def draw_boxes_and_show(cv_image, boxes, title='N'):
temp_image = cv2.cvtColor(cv_image, cv2.COLOR_GRAY2RGB)
for box in boxes:
draw_box(temp_image, box)
cv2.imshow(title, temp_image)
cv2.waitKey(0)
class BaseKnnMatcher(object):
distance_threshold = 0
def __init__(self, source_dir):
self.model, self.label_map = self.get_model_and_label_map(source_dir)
#staticmethod
def get_model_and_label_map(source_dir):
responses = []
label_map = []
samples = numpy.empty((0, KNN_SQUARE_SIDE * KNN_SQUARE_SIDE), numpy.float32)
for label_idx, filename in enumerate(os.listdir(source_dir)):
label = filename[:filename.index('.png')]
label_map.append(label)
responses.append(label_idx)
image = cv2.imread(os.path.join(source_dir, filename), 0)
suit_image_standard_size = cv2.resize(image, (KNN_SQUARE_SIDE, KNN_SQUARE_SIDE))
sample = suit_image_standard_size.reshape((1, KNN_SQUARE_SIDE * KNN_SQUARE_SIDE))
samples = numpy.append(samples, sample, 0)
responses = numpy.array(responses, numpy.float32)
responses = responses.reshape((responses.size, 1))
model = cv2.KNearest()
model.train(samples, responses)
return model, label_map
def predict(self, image):
image_standard_size = cv2.resize(image, (KNN_SQUARE_SIDE, KNN_SQUARE_SIDE))
image_standard_size = numpy.float32(image_standard_size.reshape((1, KNN_SQUARE_SIDE * KNN_SQUARE_SIDE)))
closest_class, results, neigh_resp, distance = self.model.find_nearest(image_standard_size, k=1)
if distance[0][0] > self.distance_threshold:
return None
return self.label_map[int(closest_class)]
class DigitKnnMatcher(BaseKnnMatcher):
distance_threshold = 10 ** 10
class MeterValueReader(object):
def __init__(self):
self.digit_knn_matcher = DigitKnnMatcher(source_dir='templates')
#classmethod
def get_symbol_boxes(cls, cv_image):
ret, thresh = cv2.threshold(cv_image.copy(), 150, 255, cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
symbol_boxes = []
for contour in contours:
x, y, width, height = cv2.boundingRect(contour)
# You can test here for box size, though not required in your example:
# if cls.is_size_of_digit(width, height):
# symbol_boxes.append((x, y, x+width, y+height))
symbol_boxes.append((x, y, x+width, y+height))
return symbol_boxes
def get_value(self, meter_cv2_image):
symbol_boxes = self.get_symbol_boxes(meter_cv2_image)
symbol_boxes.sort() # x is first in tuple
symbols = []
for box in symbol_boxes:
symbol = self.digit_knn_matcher.predict(crop(meter_cv2_image, box))
symbols.append(symbol)
return symbols
if __name__ == '__main__':
# If you want to see how boxes detection works, uncomment these:
# img_bw = cv2.imread(os.path.join('original.png'), 0)
# boxes = MeterValueReader.get_symbol_boxes(img_bw)
# draw_boxes_and_show(img_bw, boxes)
# Uncomment to generate templates from image
# import random
# TEMPLATE_DIR = 'templates'
# img_bw = cv2.imread(os.path.join('original.png'), 0)
# boxes = MeterValueReader.get_symbol_boxes(img_bw)
# for box in boxes:
# # You need to label templates manually after extraction
# cv2.imwrite(os.path.join(TEMPLATE_DIR, '%s.png' % random.randint(0, 1000)), crop(img_bw, box))
img_bw = cv2.imread(os.path.join('original.png'), 0)
vr = MeterValueReader()
print vr.get_value(img_bw)
in my case, there are 2 ways of getting image to resize/crop.
upload normal image file
giving base64 string data of image
in 1. case, resize and crop is working well:
f = Image.open(uploaded_image)
new_width, new_height = 1200, 630
wpercent = (new_width / float(f.size[0]))
hsize = int((float(f.size[1]) * float(wpercent)))
if f.mode != "RGB":
f = f.convert('RGB')
og_img = None
if f.size[0] < new_width:
#upscale
og_img = f.resize((new_width, hsize), Image.BICUBIC)
elif f.size[0] >= new_width:
#downscale
og_img = f.resize((new_width, hsize), Image.ANTIALIAS)
og_img = og_img.crop((0, 0, 1200, 630))
resized/cropped image:
in 2. case, the code is the same as above with slight change in:
base64_image = str(request.POST.get('base64_image')).split(',')[1]
imgfile = open('/'.join([settings.MEDIA_ROOT, 'test.png' ]), 'w+b')
imgfile.write(decodestring(base64_image))
imgfile.seek(0)
f = Image.open(imgfile)
#.. as above
but the resized/cropped image:
why is it in 2.case bad in quality and size? (black bottom part..) what am I doing wrong? am I reading the base64 string in wrong way?
I found a website which has many interesting things in it.It has 2(there are many) tools which maybe can help you.The 1th tool converts image to base64 and the 2th tool minifies the size of image (up to 70% save).
http://www.w3docs.com/tools/minimage/
http://www.w3docs.com/tools/image-base64
I've a color list file I read it into a python list and I'd like to create one (or several) image(s) composed by squares with background color read from file and as foreground html string of the color (written with white). I.e. I read #ff0000 from input file then I create a 100x100 square with red background and a white string "#ff0000" as foreground...and so on for each color in input file.
This is my script:
#!/usr/bin/env python
from gimpfu import *
def readColors(ifc):
"""Read colors from input file and return a python list with all them"""
a = []
fd = open(ifc,"r")
for i in fd:
if not i.startswith("//"):#skip comment lines
a.append(i.rstrip('\n'))
return a
def rgb2html(col):
"""Converts a color: from (255,255,255) to #ffffff"""
r,g,b = col
return "#%x%x%x" % (r,g,b)
def html2rgb(col):
"""Converts a color: from #ffffff to (255,255,255)"""
s=col.strip('#')
r=int(s[:2],16)
g=int(s[2:4],16)
b=int(s[4:6],16)
return r,g,b
def nextColor():
"""Gets next html color from color list"""
col = nextColor.array[nextColor.counter]
nextColor.counter +=1
return col
def isNextColor():
"""Is there another color or list is over?"""
return nextColor.counter<isNextColor.colorslenght
def isPageEnded(y,YSIZE):
"""Is there enough room to draw another square?"""
return (y+100)>=YSIZE
def newPage(XSIZE,YSIZE):
"""Returns a new image"""
return gimp.Image(XSIZE,YSIZE,RGB)
def createImage(color,text):
"""Draws a square filled with color and white color text. It works!"""
gimp.set_foreground((255,255,255))#text color
gimp.set_background(color) #background color
image = gimp.Image(100,100,RGB)
back = gimp.Layer(image,"font",100,100,RGB_IMAGE,100,NORMAL_MODE)
image.add_layer(back,1)
back.fill(BACKGROUND_FILL)
lay = back.copy()
lay.name = "font"
image.add_layer(lay,0)
lay = pdb.gimp_text_fontname(image,None,2,100/4,text,2,True,18,PIXELS,"Sans")
image.merge_down(lay, NORMAL_MODE)
image.flatten()
return image
def drawRect(image,x,y):
"""Here I'd like to copy the result of createImage at current x,y position of current image. It doesn't work!"""
text = nextColor()
color = html2rgb(text)
img = createImage(color,text)
drawable = pdb.gimp_image_active_drawable(image)
image.disable_undo()
pdb.gimp_selection_none(image)
pdb.gimp_image_select_rectangle(image, 2, x, y, 100, 100)
if pdb.gimp_edit_named_copy_visible(img, "buffer"):
floating_sel = pdb.gimp_edit_named_paste(drawable, "buffer", TRUE)
pdb.gimp_selection_none(image)
image.flatten()
gimp.Display(image)#to debug
image.enable_undo()
def savePage(image,directory,filename):
"""Saves composed image to filename"""
drawable = pdb.gimp_image_active_drawable(image)
pdb.file_png_save(image, drawable, directory+"\\"+filename, filename, 0,9,1,0,0,1,1)
def draw(ifile,savedir,prefix):
"""Main method. it manage page's room, slicing it in several 100x100 squares"""
YSIZE = 1000
XSIZE = 1000
x = y = pc = 0
colorArray = readColors(ifile)
nextColor.counter = 0
nextColor.array = colorArray
isNextColor.colorslenght = len(colorArray)
pdb.gimp_context_push()
image = newPage(XSIZE,YSIZE)
while(isNextColor()):
drawRect(image,x,y)
x += 100 # move to next column
if x+100>=XSIZE:#move to next row
x = 0
y += 100
if isPageEnded(y,YSIZE):
savePage(image,savedir,prefix+str(pc)+".png")
gimp.Display(image)#to debug
pc += 1
image = newPage(XSIZE,YSIZE)
x = 0
y = 0
savePage(image,savedir,prefix+str(pc)+".png")#save last page
pdb.gimp_context_pop()
ifc = '<path to color list file>\\colors.txt'
ofc = '<path to output directory>\\palette'
prefix = 'table' #prefix for each file(i.e.: table0.png, table1.png...)
draw(ifc,ofc,prefix) #main method call
My current problem is with drawRect method. I can't copy image returned by createImage method at coords x,y of bigger image in drawRect method. In drawRect method I tried to used gimp's "copy into selection": select an area, and paste in it stuff copied from another image. But I have a trouble with layers and I can't get image copied at right position.
Just for completeness this are few lines from ifc file:
#b6ffff
#f079f3
#9979f3
#79c2f3
#7a79f3
#79f380
#f3799a
Thanks in advance for any help.
Alberto
Maybe it could be useful for someone else (it must be saved as "draw-colors.py" and copied to GIMP 2/lib/gimp/2.0/plug-ins folder):
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from gimpfu import *
def readColors(ifile):
"""Read colors from input file and return a python list with all them"""
a = []
fd = open(ifile,"r")
for i in fd:
if not i.startswith('//'):
a.append(i)
return a
def rgb2html(col):
"""Converts a color: from (255,255,255) to #ffffff"""
r,g,b = col
return "#%x%x%x" % (r,g,b)
def html2rgb(col):
"""Converts a color: from #ffffff to (255,255,255)"""
s=col.strip('#')
r=int(s[:2],16)
g=int(s[2:4],16)
b=int(s[4:6],16)
return r,g,b
def nextColor():
"""Gets next html color from color list"""
col = html2rgb(nextColor.array[nextColor.counter])
nextColor.counter +=1
return col
def isNextColor():
"""Is there another color or list is over?"""
return nextColor.counter<isNextColor.colorslenght
def isPageEnded(y,sizey):
"""Is there enough room to draw another square?"""
return (y+100)>=sizey
def newPage(sizex,sizey):
"""Returns a new image"""
image = pdb.gimp_image_new(sizex, sizey, RGB)
layer = pdb.gimp_layer_new(image, sizex, sizey, RGB, "layer", 0, 0)
pdb.gimp_image_add_layer(image, layer, 0)
drw = pdb.gimp_image_active_drawable(image)
pdb.gimp_context_set_background((255,255,255))
pdb.gimp_drawable_fill(drw, BACKGROUND_FILL)
pdb.gimp_context_set_brush('Circle (01)')
return image
def savePage(image,filename):
"""Saves composed image to filename"""
layers = image.layers
last_layer = len(layers)-1
try:
disable=pdb.gimp_image_undo_disable(image)
pdb.gimp_layer_add_alpha(layers[0])
pdb.plug_in_colortoalpha(image,image.active_layer,(0,0,0))
layer = pdb.gimp_image_merge_visible_layers(image, 1)
enable = pdb.gimp_image_undo_enable(image)
pdb.file_png_save(image, image.active_layer, filename, filename, 0,9,1,0,0,1,1)
except Exception as e:
raise e
def drawRect(x,y,color,image):
"""draw a single square"""
text = rgb2html(color)
pdb.gimp_image_select_rectangle(image, 2, x, y, 100, 100)
pdb.gimp_context_set_background(color)
pdb.gimp_edit_fill(image.active_layer, 1)
try:
text_layer = pdb.gimp_text_fontname(image, None, x, y+(100/2), text, 2, 1, 18, 0, "Sans")
pdb.gimp_image_merge_down(image, text_layer, 0)
except Exception as e:
raise e
def draw(ifile,odir,prefix,sizex,sizey):
"""Main method. it manage page's room, slicing it in several 100x100 squares"""
colorArray = readColors(ifile)
nextColor.counter = 0
nextColor.array = colorArray
isNextColor.colorslenght = len(colorArray)
pc = x = y = 0
image = newPage(sizex,sizey)
try:
while(isNextColor()):
pdb.gimp_context_push()
drawRect(x,y,nextColor(),image)
x += 100#cambia colonna
if x+100>=sizex:#cambia riga
x = 0
y += 100
if isPageEnded(y,sizey):#salva pagina
savePage(image,odir+'\\'+prefix+str(pc)+".png")
pc += 1
image = newPage(sizex,sizey)
x = y = 0
savePage(image,odir+'\\'+prefix+str(pc)+".png")
pdb.gimp_context_pop()
except Exception as e:
raise e
register(
"draw-colors",
N_("Create a color map from a text color file"),
"Create a color map from a text color file",
"Alberto",
"#Copyright Alberto 2014",
"2014/10/21",
N_("Draw Colors..."),
"",
[
(PF_FILE, "ifile", N_("Color input file:"), 'default\\input\\colorfile\\path\\colorlist.txt'),
(PF_DIRNAME, "odir", N_("Path for png export:"), 'default\\output\\path'),
(PF_STRING, "prefix", N_("Filename prefix for export:"), "table"),
(PF_INT8, "sizex", N_("Image's x size:"), 1024),
(PF_INT8, "sizey", N_("Image's y size:"), 1024)
],
[],
draw, #main method call
menu="<Image>/Filters/Alberto",
domain=("gimp20-python", gimp.locale_directory)
)
main()
Output example: