46 This is a user configurable option to match the color schema of your terminal for using the ascii 47 imaging options. If your terminal is dark text on a light background, set to False. If your 48 terminal is light text on a dark background, set to True. You can safely ignore this if you 49 are using the GUI version. 54 TOGGLE_PRESSED =
False 66 Create intro/directions slide for the thresholding Python script. 68 @return image A 1080x1080 black 3 color image with red text (CV Mat) 70 image = np.zeros((1000, 1000, 3))
71 font = cv2.FONT_HERSHEY_SIMPLEX
72 text_color = (0, 0, 255)
73 text_lines = [
"Use this program to determine the optimal threshold", \
74 "value for the input vid. Adjust the \"Threshold\"", \
75 "slider until the fog around the moon disappears and the", \
76 "edge of the moon is crisp, without losing parts of the", \
77 "edge. When you are happy with the results, use the value", \
78 "on the slider in this windowas the value for ", \
79 "BLACKOUT_THRESH in settings.cfg.", \
80 "",
"",
"",
"",
"",
"", \
81 "To exit this script, press ESC", \
83 "To begin testing the image, or return to these directions,", \
84 "use the \"Directions\" slider" 86 for i, j
in enumerate(text_lines):
87 image = cv2.putText(image, j, (50, 50*(i+1)), font, 1, text_color, 2, cv2.LINE_AA)
92 This is a terminal-only version of the fog removal code. In this loop, the user is prompted 93 for a threshold value to test or to exit by entering "q". The in_frame param passes through to 96 @param in_frame The input 3-channel OpenCV image 98 print(
"=======================================================================")
99 print(
"Use this program to determine the optimal threshold value for the input vid. ASCII mode is enabled for use in terminals without GUI access. Try to make any fog around the moon disappear to make the moon appear with a crisp edge. Don't overdo it and lose some of the edge though! The original image uses threshold 0, the max value of 255 will make all but the brightest spots disappear. When you are happy with the results, use the value you entered as the value for BLACKOUT_THRESH in settings.cfg.\n")
100 print(
"=======================================================================")
101 local_exit_toggle =
True 102 in_frame = cv2.cvtColor(in_frame, cv2.COLOR_BGR2GRAY)
103 while (local_exit_toggle):
104 print(
"Enter a value between (0-255) or \"q\" to exit")
105 local_string = input(
"Entry:")
106 if (local_string ==
'q')
or (local_string ==
'Q'):
107 local_exit_toggle =
False 108 elif local_string.isdigit():
109 if int(local_string) < 256:
112 print(
"You entered an invalid integer value, please choose between 0-255")
114 print(
"Unrecognized characters in entry. Try again")
119 This function does the heavy lifting for the ASCII version of this code. The input image 120 is cropped to ignore as much black background as possible, then resized to fit the user's 121 terminal (using output from `tput`). The image is thresholded, and the output from this 122 thresholding operaiton is converted to a string of ASCII characters. There are 97 characters 123 in the grayscale list. If the user has a black background, as determined by the global 124 variable BLACK_BACK, the order of ASCII characters are reversed. After printing our "image", 125 the user is informed if the image was resized and reminded of what value they entered. 127 @param in_frame The input 1-channel OpenCV image 128 @param thresh An integer between 0-255 to represent the threshold of to test here 139 local_width = int(subprocess.check_output([
"tput",
"cols"]).decode(
"ascii").strip(
'\n'))
142 ascii_list = [
"@",
"M",
"B",
"H",
"E",
"N",
"R", "#", "K", "W", "X", "D", "F", "P", "Q", "A", "S", "
U", "Z", "b", "d", "e", "h", "x", "*", "8", "G", "m", "&", "0", "4", "L", "O", "V", "Y", "k", "p", "q", "5", "T", "a", "g", "n", "s", "6", "9", "o", "w", "z", "$", "C", "I", "
u", "2", "3", "J", "c", "f", "
r", "y", "%", "1", "v", "7", "l", "+", "i", "t", "[", "]", "", "{", "}", "?", "j", "|", "(", ")", "=", "~", "!", "-", "/", "<", ">", "\\", "\"", "^", "_", "'", ";", ",", ":", "`", ".", " ", " "]
149 ascii_ratio = 256/len(ascii_list)
152 contours, hierarchy = cv2.findContours(in_frame, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
157 for cont
in contours:
159 xxx, yyy, www, hhh = cv2.boundingRect(cont)
163 box = xxx, yyy, www, hhh
166 xxx, yyy, www, hhh = box
168 roi=in_frame[yyy:yyy+hhh, xxx:xxx+www]
172 if (roi.shape[0] > local_width):
173 roi = imutils.resize(roi, width=local_width)
175 oldcols = roi.shape[0]
178 _, roi = cv2.threshold(roi, thresh, 255, cv2.THRESH_TOZERO)
180 rows, cols = roi.shape
181 print(
"generating image...")
182 for i
in range(0, rows):
183 for j
in range(0, cols):
185 picstring += ascii_list[int(roi[i, j]/ascii_ratio)]
189 print(
"Your terminal is", local_width,
" pixels wide, but the cropped raw image was", oldcols,
"pixels wide. Your output has been resized.")
190 print(
"The above image threshold value was", thresh)
195 Check if arg is a valid file that already exists on the file system. 197 @param parser the argparse object 198 @param arg the string of the filename we want to test 202 arg = os.path.abspath(arg)
203 if not os.path.exists(arg):
204 parser.error(
"The file %s does not exist!" % arg)
205 raise FileNotFoundError(
"The file you told the script to run on does not exist")
211 Check that the input integer for the starting frame number is valid 215 raise RuntimeError(
"%s is an invalid positive int value" % value)
221 Get parser object for this script 223 @return Parser object 225 from argparse
import ArgumentParser, ArgumentDefaultsHelpFormatter
226 parser = ArgumentParser(description=__doc__, formatter_class=ArgumentDefaultsHelpFormatter)
227 parser.add_argument(
"-f",
"--file", dest=
"filename", required=
True,\
228 type=
lambda x:
is_valid_file(parser, x), help=
"video input FILE", metavar=
"FILE")
229 parser.add_argument(
"-n",
"--nth_frame", dest=
"max_frame", required=
False,\
230 type=check_positive, help=
"Use the nth frame of the video to test fog", \
231 nargs=
None, default=100, metavar=
'N')
232 parser.add_argument(
"-a",
"--ascii", dest=
"ascii_toggle", required=
False, action=
"store_true",\
233 help=
"Toggle for an ascii (terminal) only version of this script", default=
False)
238 Perform primary functions of this script. 239 Command line arguments are first parsed to get the file name on which we want to operate. Then, 240 we ensure that this is a valid file. The video file is opened and the first frame is read. 241 We then create our output window of size 1080x1080 and trackbars for the Directions toggle and 242 Image Threshold. If everything was successful, the window opens with the Diretions image. When 243 the user tells the Directions to toggle closed, the first frame from the video is shown after 244 conversion to grayscale and thresholded to zero. The image threshold is determined by the value 245 of the threshold trackbar. The user exits with the ESC key. On exit, the final value of the 246 threshold is printed to the terminal. 250 print(
"Operating on file:", args.filename)
252 cap = cv2.VideoCapture(args.filename)
253 ret, frame = cap.read()
255 cnt_max = args.max_frame
256 TOGGLE_ASC = args.ascii_toggle
258 ret, frame = cap.read()
264 cv2.namedWindow(
"image", cv2.WINDOW_NORMAL)
265 cv2.resizeWindow(
"image", 1080, 1080)
266 cv2.createTrackbar(
"Directions",
"image", 0, 1, nothing)
267 cv2.createTrackbar(
"Threshold",
"image", 0, 255, nothing)
276 frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
279 local_button = cv2.getTrackbarPos(
"Directions",
"image")
280 if (local_button == 0)
and (pretest == 1):
284 TOGGLE_PRESSED =
True 286 TOGGLE_PRESSED =
False 289 thresh = cv2.getTrackbarPos(
"Threshold",
"image")
290 _, outimg = cv2.threshold(frame, thresh, 255, cv2.THRESH_TOZERO)
292 cv2.imshow(
"image", outimg)
294 kill = cv2.waitKey(1) & 0xFF
296 print(
"Your final threshold value was:", thresh)
299 pretest = local_button
303 raise RuntimeError(
"ERROR: could not get frame from video")
304 cv2.destroyAllWindows()
307 if __name__ ==
"__main__":
def check_positive(value)
Check that the input integer for the starting frame number is valid.
def ascii_proc(in_frame, thresh)
This function does the heavy lifting for the ASCII version of this code.
def ascii_version(in_frame)
This is a terminal-only version of the fog removal code.
def main()
Perform primary functions of this script.
def get_parser()
Get parser object for this script.
def is_valid_file(parser, arg)
Check if arg is a valid file that already exists on the file system.
def create_directions()
Create intro/directions slide for the thresholding Python script.