Revision: 30387 http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=30387 Author: leifandersen Date: 2010-07-15 20:13:15 +0200 (Thu, 15 Jul 2010)
Log Message: ----------- Added documentation into the code, and the code looks much nicer now. Modified Paths: -------------- branches/soc-2010-leifandersen/tests/render/run.py Modified: branches/soc-2010-leifandersen/tests/render/run.py =================================================================== --- branches/soc-2010-leifandersen/tests/render/run.py 2010-07-15 17:54:53 UTC (rev 30386) +++ branches/soc-2010-leifandersen/tests/render/run.py 2010-07-15 18:13:15 UTC (rev 30387) @@ -1,3 +1,26 @@ +# ##### BEGIN GPL LICENSE BLOCK ##### +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# Contributor(s): Leif Andersen +# +# The Original Code is Copyright (C) 2010 by Leif Andersen. +# All rights reserved. +# +# ##### END GPL LICENSE BLOCK ##### + import Image import ImageChops @@ -15,12 +38,8 @@ VERBOSE = False class ImageTestCase: - '''A Render Test Case. Steps must be run in order: - 1. Constructer - 2. Render Image (if it doesn't already exist) - 3. Setup Tests - 4. Save Diff''' - + '''A Render Test Case only for use with images. It can either be used to directly + compare images, or if there is no good image, but a stored hashcode, it can compare the hashcode.''' name = '' passed = None good_path = '' @@ -40,12 +59,17 @@ mode = '' def __init__(self): + '''Simply initializes the case, but no data is created''' self.name = 'Uninitialized' self.good_hash = -1 self.test_hash = -1 self.diff_hash = -1 def setup_hash(self, blend_path, good_hash, test_path): + '''Used for setting up the case for the purpose of a hash test + blend_path: the path to the blend file for the case + good_hash: An int containing the good hash of the case + test_path: the path for the output of the test when it's rendered''' self.name = os.path.split(blend_path)[1] self.good_hash = good_hash self.blend_path = blend_path @@ -53,9 +77,10 @@ self.mode = 'Hash' def setup_image(self, blend_path, good_path, test_path): - '''Sets up a test case, with the blend_path, the known good path, and the test path - For images, the known good path is a file, - for animations, it's a folder containing all of the frames''' + '''Used for setting up the case for the purpose of a image comparison test + blend_path: the path to the blend file for the case + good_path: The path for the good image that the case will be compared too. + test_path: the path for the output of the test when it's rendered''' self.name = os.path.split(blend_path)[1] self.blend_path = blend_path self.good_path = good_path @@ -63,6 +88,10 @@ self.mode = 'Image' def generate_hash(self, image): + '''Designed mainly for internal use, but can be used for external purposes if needed + Generates a hash out of a given image + image: The image that the hash will be made from + returns: The calculated hash''' hash = 0 for i in range(0,image.size[0]): for j in range(0, image.size[1]): @@ -71,25 +100,35 @@ return hash def get_images(self): + '''Gets the good image, and test image (which assumes it's rendered), based on their + paths. Then creates a diff image out of the two other images. If the images + cannot be found, null is returned + returns: A tuplet (good_image, test_image, diff_image), or (null, null, null) if the images can't be found''' try: good_image = Image.open(self.good_path) test_image = Image.open(self.test_path) diff_image = ImageChops.difference(good_image, test_image) + return (good_image, test_image, diff_image) except (IOError, OSError): good_image = test_image = diff_image = None - finally: return (good_image, test_image, diff_image) def format_frame(self, num): + '''Designed mainly for internal use: Will return the frame number given in the four didget format blender uses. + num: The num to be converted + returns: The num in four didget format, e.g. 3 becomes 0003, 29 becomes 0029''' frame_num = str(num) while len(frame_num) < 4: frame_num = '0' + frame_num return frame_num def render_test(self): - '''Renders a single image of the first frame of the blend file. - Also changes output_path slightly''' + '''Renders the test image based on the given image path in the setup methods. + Assumes there is a global VERBOSE and BLENDER_BIN variable to be used. + Will only render the first frame of the image using the default settings (saving as a PNG though) + Changes the animation paths to the actual paths (from the given path)''' + # Render Based on whether or not it's verbose if VERBOSE: command = BLENDER_BIN + ' -b ' + self.blend_path + ' -o ' + self.test_path + '_#### -F PNG -x 1 -f 1' os.system(command) @@ -97,16 +136,25 @@ p = Popen([BLENDER_BIN, '-b', self.blend_path, '-o', self.test_path + '_####', '-F', 'PNG', '-x', '1', '-f', '1'], stdout=PIPE, stderr=PIPE, stdin=PIPE) p.wait() + # Modify the test path as needed self.test_path += '_0001.png' def image_test(self): - '''Runs the test, filling in all of the usefull fields''' + '''Performs the image comparison test, assuming that the images have already been generated. + if they have not been generated, than the testcase will be set to a fail. After the completion + of the test, the status of if the test passed or failed can be found in the passed field <testCaseName>.passed + returns: Whether or not the test passed''' try: + + # Setup Variables (good_image, test_image, diff_image) = self.get_images() self.diff_sum = 0 self.bad_pixels = 0 self.pixel_range = len(diff_image.histogram()) self.pixel_count = diff_image.size[0] * diff_image.size[1] + + # Determine the total diff, + # as well as the bad pixels for i in range(0,diff_image.size[0]): for j in range(0, diff_image.size[1]): p = diff_image.getpixel((i,j)) @@ -114,11 +162,14 @@ if p[0] + p[1] + p[2] > 10: self.bad_pixels+=1 self.difference = float(self.diff_sum)/float(self.pixel_range*self.pixel_count) + + # Set pass/fail if self.bad_pixels < self.pixel_count/5 and self.difference < 0.01: self.passed = True else: self.passed = False except (TypeError, AttributeError): + # In case the Image wasn't rendered or something else goes wrong self.passed = False self.diff_sum = -1 self.bad_pixels = -1 @@ -129,6 +180,14 @@ return self.passed def hash_test(self): + '''Performs the hash test on the image in case that the testcase is being used as a hashtest. + If the setup_image method was used rather than the setup_hash method, the test attempts to generate + a hash based on that image. It assumes that the test image has been rendered + The status of the test passing can be found in the passed field. + This method changes the value of the diff paths to the actual diff paths. + returns: Whether or not the test passed''' + + ### TODO, rewrite...bad code ### if test_image == None: try: test_image = Image.open(self.test_path) @@ -153,17 +212,16 @@ self.passed = False def save_diff(self, output_path): - '''Saves the diff image to output_path''' + '''Saves the diff image of the testcase to output_path + output_path: The path to save the diff image''' (good_image, test_image, diff_image) = self.get_images() if diff_image != None: self.diff_path = output_path diff_image.save(output_path) - else: - self.diff_path = 0 class AnimationTestCase(ImageTestCase): - '''''' - + '''A Render Test Case only for use with animations. It can either be used to directly + compare images, or if there is no good image, but a stored hashcode, it can compare the hashcode.''' passed_arr = [] good_path_arr = [] test_path_arr = [] @@ -175,6 +233,7 @@ diffference_arr = [] def __init__(self): + '''Simply initializes the case, but no data is created''' self.name = 'Uninitialized' self.passed_arr = [] self.good_path = '' @@ -195,7 +254,10 @@ self.diff_hash = -1 def setup_hash(self, blend_path, good_hash, test_path): - '''''' + '''Used for setting up the case for the purpose of a hash test + blend_path: the path to the blend file for the case + good_hash: An int containing the good hash of the case + test_path: the path for the output folder of the test when it's rendered''' self.name = os.path.split(blend_path)[1] self.good_hash = good_hash self.blend_path = blend_path @@ -209,7 +271,10 @@ self.mode = 'Hash' def setup_image(self, blend_path, good_path, test_path): - '''''' + '''Used for setting up the case for the purpose of a image comparison test + blend_path: the path to the blend file for the case @@ Diff output truncated at 10240 characters. @@ _______________________________________________ Bf-blender-cvs mailing list Bf-blender-cvs@blender.org http://lists.blender.org/mailman/listinfo/bf-blender-cvs