4
\$\begingroup\$

Background

I've got OpenCV & Python installed on a Docker container which is on a http server to process images and serve them. The user interface is through the web; user inputs an image and some values; the values are collected through a form and the values and image paths (hashed input and output paths) are sent through JSON to a bash script which runs the Python code. There are two Python scripts; one which does the JSON input processing (cspaceIO.py), and the main processing module (cspaceFilter.py) which is only called by the first script.


Questions

  1. Is there anything here that screams "bad idea" with the flow of this approach?
  2. Do I need to worry about anything security-wise that my _sanitize() function doesn't help with?
  3. How do the python scripts look on their own?

I/O script cspaceIO.py

import argparse # command line inputs
import cspaceFilter # running the algo
import cv2 # for checking the image
import json # for i/o
"""Validator functions"""
def _sanitize(filename):
 sanitized = "".join(
 [c for c in filename
 if c.isalpha() or c.isdigit() or c in ['.', '_', '-', '/']]).rstrip()
 return sanitized
def _checkimg(imgPath):
 img = cv2.imread(imgPath)
 if img is None:
 invalidmsg = ("%s is an invalid image filename, "
 "did not load image." % imgPath)
 raise argparse.ArgumentTypeError(invalidmsg)
 return img
def _checkcspace(cspaceLabel):
 validLabels = ['BGR', 'HSV', 'HLS', 'Lab',
 'Luv', 'YCrCb', 'XYZ', 'Grayscale']
 if cspaceLabel not in validLabels:
 invalidmsg = ("{0} is an invalid colorspace, must be one of: "
 "{1}, {2}, {3}, {4}, {5}, {6}, {7}, or {8}."
 ).format(cspaceLabel, *validLabels)
 raise argparse.ArgumentTypeError(invalidmsg)
"""Command line parsing"""
if __name__ == "__main__":
 """To be ran from command line
 Usage example:
 python3 cspaceIO.py '{
 "paths":
 {
 "srcPath":"input/test.png",
 "maskPath":"output/test.png",
 "maskedPath":"output/test2.png"
 },
 "cspaceLabel":"BGR",
 "sliderPos":[127,255,127,255,127,255]
 }'
 """
 parser = argparse.ArgumentParser(
 description='Color threshold an image in any colorspace \
 and save it to a file.')
 parser.add_argument('jsonIn', help='JSON containing paths \
 (dict {imgPath (str), maskPath (str), maskedPath (str)}), \
 cspaceLabel (str), and sliderPos (6-long int list[])')
 args = parser.parse_args()
 # grab inputs from json
 jsonIn = json.loads(args.jsonIn)
 paths = jsonIn['paths']
 srcPath = paths['srcPath']
 maskPath = paths['maskPath']
 maskedPath = paths['maskedPath']
 cspaceLabel = jsonIn['cspaceLabel']
 sliderPos = jsonIn['sliderPos']
 # check inputs
 _checkcspace(cspaceLabel)
 srcPath = _sanitize(srcPath)
 maskPath = _sanitize(maskPath)
 maskedPath = _sanitize(maskedPath)
 img = _checkimg(srcPath)
 # run the colorspace filter script
 mask, masked_img = cspaceFilter.main(img, cspaceLabel, sliderPos)
 # write the output image
 cv2.imwrite(maskPath, mask)
 cv2.imwrite(maskedPath, masked_img)

Image processing module cspaceFilter.py

import cv2
import numpy as np
"""Helper functions"""
def _cspaceSwitch(img, cspaceLabel):
 """Coverts the colorspace of img from BGR to cspaceLabel
 Keyword arguments:
 img -- the image to convert
 cspaceLabel -- the colorspace to convert to
 Returns:
 img -- img with the converted colorspace
 """
 if cspaceLabel == 'BGR':
 return img
 convert_code = {
 'HSV': cv2.COLOR_BGR2HSV,
 'HLS': cv2.COLOR_BGR2HLS,
 'Lab': cv2.COLOR_BGR2Lab,
 'Luv': cv2.COLOR_BGR2Luv,
 'YCrCb': cv2.COLOR_BGR2YCrCb,
 'XYZ': cv2.COLOR_BGR2XYZ,
 'Grayscale': cv2.COLOR_BGR2GRAY}
 img = cv2.cvtColor(img, convert_code[cspaceLabel])
 return img
def _cspaceBounds(cspaceLabel, slider_pos):
 """Calculates the lower and upper bounds for thresholding a
 colorspace based on the thresholding slider positions.
 Keyword arguments:
 cspaceLabel -- the colorspace to find bounds of; see keys in main()
 slider_pos -- positions of the thresholding trackbars; length 6 list
 Returns:
 lowerb -- list containing the lower bounds for each channel threshold
 upperb -- list containing the upper bounds for each channel threshold
 """
 if cspaceLabel is 'Grayscale':
 lowerb, upperb = slider_pos[0], slider_pos[1]
 else:
 lowerb = np.array([slider_pos[0], slider_pos[2], slider_pos[4]])
 upperb = np.array([slider_pos[1], slider_pos[3], slider_pos[5]])
 return lowerb, upperb
def _cspaceRange(img, cspaceLabel, lowerb, upperb):
 """Thresholds img in cspaceLabel with lowerb and upperb
 Keyword arguments:
 img -- the image to be thresholded
 cspaceLabel -- the colorspace to threshold in
 Returns:
 mask -- a binary image that has been thresholded
 """
 img = _cspaceSwitch(img, cspaceLabel)
 mask = cv2.inRange(img, lowerb, upperb)
 return mask
def _applyMask(img, mask):
 """Applies a mask to an image
 Keyword arguments:
 img -- the image to be masked
 mask -- the mask (non-zero values are included, zero values excluded)
 Returns:
 masked_img -- the input img with mask applied
 """
 masked_img = cv2.bitwise_and(img, img, mask=mask)
 return masked_img
"""Main public function"""
def main(img, cspaceLabel, slider_pos):
 """Computes the colorspace thresholded image based on
 slider positions and selected colorspace.
 Inputs:
 img -- input image
 cspaceLabel -- colorspace to filter the image in
 slider_pos -- positions of the six sliders (6-long int list)
 returns
 mask -- mask created from thresholding the image
 masked_img -- masked image
 """
 lowerb, upperb = _cspaceBounds(cspaceLabel, slider_pos)
 mask = _cspaceRange(img, cspaceLabel, lowerb, upperb)
 masked_img = _applyMask(img, mask)
 return mask, masked_img
asked Aug 27, 2017 at 20:22
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$
sanitized = "".join(
 [c for c in filename
 if c.isalpha() or c.isdigit() or c in ['.', '_', '-', '/']]).rstrip()

Just a small improvement - as strings are sequences, you may change it to

sanitized = "".join(
 [c for c in filename
 if c.isalpha() or c.isdigit() or c in "._-/"])

( .rstrip() is superfluous as you don't allow whitespaces.)

answered Aug 27, 2017 at 22:35
\$\endgroup\$
1
  • \$\begingroup\$ Great catch there, pushing straight to development with that one. \$\endgroup\$ Commented Aug 27, 2017 at 23:01

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.