# Testing EVE | Adrian F. Clark | alien@essex.ac.uk This file contains a series of tests of the routines in EVE, the Easy Vision Environment. They are intended both for checking the correct operation of the routines and as an _aide memoire_ as to how to invoke them. The tests are executed by the incantation python3 -m doctest testing-eve.md If all the tests succeed, there will be no output; if you want to see the detail of the individual tests, add the `-v` qualifier. If any of the tests fail, you will see a summary of the output that was expected and what was actually produced. These tests and associated descriptions are written in Markdown and so can easily be converted by [`Pandoc`](https://pandoc.org) into other forms. To convert this file to (say) PDF, use the incantation pandoc -o testing-eve.pdf testing-eve.md ## Image creation and returning the values in an image Our first test imports the EVE module, creates an image from a tuple of dimensions and checks its size. It then checks that all the elements are set to zero. If this doesn't work, nothing else stands a chance. >>> import eve, numpy, math >>> im = eve.image ((1, 1, 10)) >>> eve.sizes (im) (1, 1, 10) >>> list (im[0][0]) [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] We can also create images from a list of dimensions. >>> im = eve.image ([3, 4, 5]) >>> eve.sizes (im) (3, 4, 5) Finally, we can create an image from another image. >>> im2 = eve.image (im) >>> eve.sizes (im2) (3, 4, 5) A pair of EVE routines were written to support these tests, built on top of the two we have just tested. The first creates an image and sets its pixels to the supplied values while the other returns the pixel values of an image as a list to simplify checking. These will be used many times in the remainder of the tests and so need to be checked here, before they are used 'in anger.' >>> im = eve.image_from_values ((3, 3, 2), [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, ... 11, 12,13, 14, 15, 16, 17, 18]) >>> eve.image_to_values (im) [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0] We need to ensure that the indexing of images is correct. Create `im` with one pixel set to a different value from the others, then check it is where it should be. >>> im = eve.image_from_values ((3, 5, 1), [1, 1, 1, 1, 1, 1, 1, 2, 1, ... 1, 1, 1, 1, 1, 1]) >>> im[1,2,0] 2.0 Although floating-point is the default representation of pixels, we can create images whose pixels are other data types. Let us do an unsigned byte image first. >>> im = eve.image ((5, 3, 1), type=numpy.uint8) >>> eve.set (im, 255) >>> eve.image_to_values (im) [255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255] Make sure complex works too. >>> im = eve.image ((10, 12, 1), type=numpy.complex64) >>> eve.set (im, 2.0+3.0j) >>> im[2,1,0].real 2.0 >>> im[2,1,0].imag 3.0 ## Setting and copying images When we make a copy of an image, it should be a separate instance, meaning that if we modify the copy, the original should be unchanged and _vice versa_. >>> im = eve.image_from_values ((3, 5, 1), [1, 1, 1, 1, 1, 1, 1, 2, 1, ... 1, 1, 1, 1, 1, 1]) >>> dup = eve.copy (im) >>> dup[0,0,0] = 888 >>> im[0,0,0] 1.0 We should be able to set an image to a constant value. As the internal representation of images is floating-point, it makes sense to ensure we can set the pixels to non-integer values. Having set the values to a non-zero value, we can also check that the routine to zero values works. >>> eve.set (dup, 0.1) >>> eve.image_to_values (dup) [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1] >>> eve.zero (dup) >>> eve.image_to_values (dup) [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] We can set multi-channel pixels to a list of values. >>> im = eve.image ((5, 3, 3)) >>> v = [1.5, 2.6, 0.9] >>> eve.set (im, v) >>> v = im[2,1,0] >>> abs (v - 1.5) < 1.0e-5 True >>> v = im[2,1,1] >>> abs (v - 2.6) < 1.0e-5 True >>> v = im[2,2,2] >>> abs (v -0.9) < 1.0e-5 True There is a routine that sets an image to a pattern of values, with different increments along the `y`, `x`, and `c` dimensions and storing their product as the value of each pixel. Let us ensure that routine does what we expect. >>> im = eve.image ((5, 3, 2)) >>> eve.set_to_pattern (im) >>> eve.image_to_values (im) [0.0, 1.0, 10.0, 11.0, 20.0, 21.0, 100.0, 101.0, 110.0, 111.0, 120.0, 121.0, 200.0, 201.0, 210.0, 211.0, 220.0, 221.0, 300.0, 301.0, 310.0, 311.0, 320.0, 321.0, 400.0, 401.0, 410.0, 411.0, 420.0, 421.0] Armed with that routine, let us ensure we can get an individual channel of an image. >>> im = eve.image ((5, 3, 2)) >>> eve.set_to_pattern (im) >>> c = eve.get_channel (im, 1) >>> eve.image_to_values (c) [1.0, 11.0, 21.0, 101.0, 111.0, 121.0, 201.0, 211.0, 221.0, 301.0, 311.0, 321.0, 401.0, 411.0, 421.0] Similarly, ensure we can set a channel of an image. >>> im = eve.image ((5, 3, 2)) >>> c = eve.image ((5, 3, 1)) >>> eve.set_to_pattern (c) >>> eve.set_channel (im, 1, c) >>> eve.image_to_values (im) [0.0, 0.0, 0.0, 10.0, 0.0, 20.0, 0.0, 100.0, 0.0, 110.0, 0.0, 120.0, 0.0, 200.0, 0.0, 210.0, 0.0, 220.0, 0.0, 300.0, 0.0, 310.0, 0.0, 320.0, 0.0, 400.0, 0.0, 410.0, 0.0, 420.0] There is a routine to set a region of an image, so let us make sure this works. >>> im = eve.image ((5, 3, 2)) >>> eve.set_region (im, 1, 1, 3, 2, 255.0) >>> eve.image_to_values (im) [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 255.0, 255.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] Similarly, there is a routine to extract a region from an image. >>> im = eve.image ((10, 5, 2)) >>> eve.set_to_pattern (im) >>> reg = eve.region (im, 4, 7, 2, 4) >>> eve.image_to_values (reg) [420.0, 421.0, 430.0, 431.0, 520.0, 521.0, 530.0, 531.0, 620.0, 621.0, 630.0, 631.0] EVE has two further routines for setting patterns in images. The first simply sets an image to a plane or ramp. >>> im = eve.image ((5, 3, 2)) >>> eve.ramp (im) >>> eve.image_to_values (im) [0.0, 1.0, 1.0, 2.0, 2.0, 3.0, 1.0, 2.0, 2.0, 3.0, 3.0, 4.0, 2.0, 3.0, 3.0, 4.0, 4.0, 5.0, 3.0, 4.0, 4.0, 5.0, 5.0, 6.0, 4.0, 5.0, 5.0, 6.0, 6.0, 7.0] The second sets an image to the zone plate pattern proposed by Tran Thong. >>> im = eve.image ((5, 3, 2)) >>> eve.thong (im) >>> epts = [64.40077, 64.40077, 64.02021, 64.02021, 64.40077, 64.40077, 73.76999, 73.76999, 128.80423, 128.80423, 73.76999, 73.76999, 128.80423, 128.80423, 192.0, 192.0, 128.80423, 128.80423, 73.76999, 73.76999, 128.80423, 128.80423, 73.76999, 73.76999, 64.40077, 64.40077, 64.02021, 64.02021, 64.40077, 64.40077] >>> pts = eve.image_to_values (im) >>> eve.compare_lists (eve.flatten_list (epts), eve.flatten_list (pts), ... tol=1.0e-5) 0 ## Simple image operations Like most image processing and analysis packages, many operations are performed on pixels independently of each other. One of the simplest is clipping, ensuring the pixels lie within a range. >>> im = eve.image ((5, 3, 2)) >>> eve.thong (im) >>> eve.clip (im, 65.0, 75.0) >>> im[0,0,0] 65.0 >>> im[3,1,0] 75.0 One very common image operation is contrast-stretching. >>> im = eve.image ((5, 3, 2)) >>> im[0,1,0] = -15.0 >>> im[0,1,1] = 15.0 >>> eve.contrast_stretch (im) >>> im[0,1,0] 0.0 >>> im[0,1,1] 255.0 >>> im[0,2,1] 127.5 ## Simple image statistics The first thing to do is set up an image and check we can obtain its extremal values and the sum of the pixels. >>> im = eve.image ((5, 3, 2)) >>> im[3, 2, 0] = 1.0 >>> im[3, 1, 1] = -1.0 >>> eve.minval (im) -1.0 >>> eve.maxval (im) 1.0 >>> eve.extrema (im) [-1.0, 1.0] >>> eve.sum (im) 0.0 Now test that the mean is calculated sensibly. >>> im = eve.image ((5, 3, 2)) >>> im[0,0,0] = 30 >>> eve.mean (im) 1.0 It is a little more tricky to figure out values for making the standard deviation come out to be a nice number, so we set them explicitly. The difference is 1 everywhere, so we end up calculating $$\sqrt{\frac{18}{17}} = 1.0289916$$ which is the sample standard deviation. >>> im = eve.image_from_values ((6, 3, 1), ... [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, ... -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0]) >>> eve.variance (im) 1.0588236 >>> eve.sd (im) 1.0289916 There is also a routine which delivers all these statistics in one call. >>> eve.statistics (im) [-1.0, 1.0, 0.0, 1.0289916] As well as calculating the statistics, we can also set an image to have a given mean and standard deviation. We cannot compare for exact equality here; instead, we make sure the difference between the mean we have tried to set the image to and the calculated one is small. We use the same approach for comparing the standard deviation. >>> im = eve.image ((50, 50, 2)) >>> eve.thong (im) >>> eve.set_mean_sd (im, 12.0, 4.5) >>> lo, hi, ave, sd = eve.statistics (im) >>> abs (ave - 12) < 1.0e-5 True >>> abs (sd - 4.5) < 1.0e-5 True ## Two-image statistics Let us check that the correlation coefficient does what we expect it to. >>> im1 = eve.image ((5, 3, 1)) >>> eve.set_to_pattern (im1) >>> im2 = eve.copy (im1) >>> im2 /= 10 >>> eve.correlation_coefficient (im1, im2) 1.0 >>> im2 = eve.reverse_contrast (im2) >>> eve.correlation_coefficient (im1, im2) -1.0 Building on the correlation coefficient, we can calculate the signal-to-noise ratio. One of the limiting cases is when the images are identical: the SNR is then infinite. If the correlation coefficient is less than zero, it returns zero. >>> eve.snr (im1, im1) inf >>> eve.snr (im1, im2) 0.0 >>> im2 = eve.copy (im1) >>> im2[0,0,0] += 613 >>> eve.snr (im1, im2) 1.0001526644702168 The correlation and SNR are ways of assessing the similarity of a pair of images. There are many other ways to do this, and perhaps the most obvious are the sum-squared difference and its close relative the mean-squared error. >>> im1 = eve.image ((5, 3, 1)) >>> eve.set_to_pattern (im1) >>> im2 = eve.copy (im1) >>> eve.ssd (im1, im2) 0.0 >>> im2[0,0,0] += 1.0 >>> eve.ssd (im1, im2) 1.0 >>> v = eve.mse (im1, im2) >>> abs (v - 0.06666666666666667) < 1.0e-5 True We can also perform a pixel-by-pixel comparison of two images, counting the number of pixels for which they differ. We shall use the quite often in the remaining tests. >>> im1 = eve.image ((5, 3, 2)) >>> eve.set_to_pattern (im1) >>> im2 = eve.copy (im1) >>> eve.compare (im1, im2) 0 >>> im2[0,0,0] += 1 >>> eve.compare (im1, im2, report=0) 1 ## Routines that involve the geometry of images Let us start with routines the reflect the image along various axes. First, a traditional transpose, a reflection in the main diagonal. >>> im = eve.image ((5, 7, 2)) >>> eve.set_to_pattern (im) >>> res = eve.image_from_values ((7, 5, 2), [ ... 0, 1, 100, 101, 200, 201, 300, 301, 400, 401, ... 10, 11, 110, 111, 210, 211, 310, 311, 410, 411, ... 20, 21, 120, 121, 220, 221, 320, 321, 420, 421, ... 30, 31, 130, 131, 230, 231, 330, 331, 430, 431, ... 40, 41, 140, 141, 240, 241, 340, 341, 440, 441, ... 50, 51, 150, 151, 250, 251, 350, 351, 450, 451, ... 60, 61, 160, 161, 260, 261, 360, 361, 460, 461]) >>> tr = eve.transpose (im) >>> eve.compare (tr, res) 0 Next, horizontal and vertical reflections. >>> im = eve.image ((5, 7, 2)) >>> eve.set_to_pattern (im) >>> res = eve.image_from_values ((5, 7, 2), [ ... 60.0, 61.0, 50.0, 51.0, 40.0, 41.0, 30.0, ... 31.0, 20.0, 21.0, 10.0, 11.0, 0.0, 1.0, ... 160.0, 161.0, 150.0, 151.0, 140.0, 141.0, 130.0, ... 131.0, 120.0, 121.0, 110.0, 111.0, 100.0, 101.0, ... 260.0, 261.0, 250.0, 251.0, 240.0, 241.0, 230.0, ... 231.0, 220.0, 221.0, 210.0, 211.0, 200.0, 201.0, ... 360.0, 361.0, 350.0, 351.0, 340.0, 341.0, 330.0, ... 331.0, 320.0, 321.0, 310.0, 311.0, 300.0, 301.0, ... 460.0, 461.0, 450.0, 451.0, 440.0, 441.0, 430.0, ... 431.0, 420.0, 421.0, 410.0, 411.0, 400.0, 401.0]) >>> eve.reflect_horizontally (im) >>> eve.compare (im, res) 0 >>> im = eve.image ((5, 7, 2)) >>> eve.set_to_pattern (im) >>> res = eve.image_from_values ((5, 7, 2), [ ... 400.0, 401.0, 410.0, 411.0, 420.0, 421.0, 430.0, ... 431.0, 440.0, 441.0, 450.0, 451.0, 460.0, 461.0, ... 300.0, 301.0, 310.0, 311.0, 320.0, 321.0, 330.0, ... 331.0, 340.0, 341.0, 350.0, 351.0, 360.0, 361.0, ... 200.0, 201.0, 210.0, 211.0, 220.0, 221.0, 230.0, ... 231.0, 240.0, 241.0, 250.0, 251.0, 260.0, 261.0, ... 100.0, 101.0, 110.0, 111.0, 120.0, 121.0, 130.0, ... 131.0, 140.0, 141.0, 150.0, 151.0, 160.0, 161.0, ... 0.0, 1.0, 10.0, 11.0, 20.0, 21.0, 30.0, ... 31.0, 40.0, 41.0, 50.0, 51.0, 60.0, 61.0]) >>> eve.reflect_vertically (im) >>> eve.compare (im, res) 0 Let us follow that up with some 90-degree rotations. First, a 90$^\circ$ rotation clockwise. >>> im = eve.image ((5, 7, 2)) >>> eve.set_to_pattern (im) >>> res = eve.image_from_values ((7, 5, 2), [ ... 400, 401, 300, 301, 200, 201, 100, 101, 0, 1, 410, 411, 310, 311, ... 210, 211, 110, 111, 10, 11, 420, 421, 320, 321, 220, 221, 120, 121, ... 20, 21, 430, 431, 330, 331, 230, 231, 130, 131, 30, 31, 440, 441, ... 340, 341, 240, 241, 140, 141, 40, 41, 450, 451, 350, 351, 250, 251, ... 150, 151, 50, 51, 460, 461, 360, 361, 260, 261, 160, 161, 60, 61]) >>> rot = eve.rotate90cw (im) >>> eve.compare (rot, res) 0 Let's do the converse, an anti-clockwise 90$^\circ$ rotation. >>> im = eve.image ((5, 7, 2)) >>> eve.set_to_pattern (im) >>> res = eve.image_from_values ((7, 5, 2), [ ... 60, 61, 160, 161, 260, 261, 360, 361, 460, 461, 50, 51, 150, 151, ... 250, 251, 350, 351, 450, 451, 40, 41, 140, 141, 240, 241, 340, 341, ... 440, 441, 30, 31, 130, 131, 230, 231, 330, 331, 430, 431, 20, 21, ... 120, 121, 220, 221, 320, 321, 420, 421, 10, 11, 110, 111, 210, 211, ... 310, 311, 410, 411, 0, 1, 100, 101, 200, 201, 300, 301, 400, 401]) >>> rot = eve.rotate90acw (im) >>> eve.compare (rot, res) 0 Finally, 180$^\circ$. >>> im = eve.image ((5, 7, 2)) >>> eve.set_to_pattern (im) >>> res = eve.image_from_values ((5, 7, 2), [ ... 460, 461, 450, 451, 440, 441, 430, 431, 420, 421, 410, 411, 400, 401, ... 360, 361, 350, 351, 340, 341, 330, 331, 320, 321, 310, 311, 300, 301, ... 260, 261, 250, 251, 240, 241, 230, 231, 220, 221, 210, 211, 200, 201, ... 160, 161, 150, 151, 140, 141, 130, 131, 120, 121, 110, 111, 100, 101, ... 60, 61, 50, 51, 40, 41, 30, 31, 20, 21, 10, 11, 0, 1]) >>> rot = eve.rotate180 (im) >>> eve.compare (rot, res) 0 Although quite unlike the reflection routines in what is does, EVE contains a routine to calculate the centroid --- also something to do with image geometry. >>> im = eve.image ((9, 11, 1)) >>> eve.set (im, 1) >>> eve.set_region (im, 3, 3, 6, 8, 10.0) >>> eve.centroid (im) [4.0, 5.0] ## Routines that pertain to colour models It is often necessary to process monochrome versions of images. For colour images, the conventional way to convert them to monochrome is to use the Y channel from the YIQ colour model. In the 21^st^ century, this is perhaps not as clear-cut a decision is it may have been 50 years earlier. The YIQ model originates from the NTSC colour analogue television standard in the USA (which was not renowned for being accurate) and assumes the CRT-based television uses a D45 phosphor, not something encountered in modern displays. Hence, we might argue that this conversion might be just as well performed by the routine `mono`, tested after this one. >>> im = eve.image_from_values ((1, 6, 3), [ ... 255, 0, 0, 255, 255, 0, 0, 255, 0, ... 0, 255, 255, 0, 0, 255, 255, 0, 255]) >>> res = eve.image_from_values ((1, 6, 1), [ ... 76.244995, 225.93, 149.685, 178.755, 29.07, 105.314995]) >>> yim = eve.rgb_to_mono (im) >>> eve.compare (res, yim) 0 When the number of channels is not three, for example with hyperspectral images, the conversion tested above is definitely not appropriate and the best we can do is to average the channels pixel by pixel. >>> im = eve.image ((3, 4, 2)) >>> eve.set_to_pattern (im) >>> v = (im[1,1,0] + im[1,1,1]) / 2 >>> mim = eve.mono (im) >>> eve.sizes (mim) (3, 4, 1) >>> abs (v - mim[1,1,0]) 0.0 Check the conversion from RGB to HSV. These values agree with the ones displayed by the well-known `xv` program but generally _not_ with OpenCV, which appears to use half-angles. >>> im = eve.image_from_values ((1, 6, 3), [ ... 255, 0, 0, 255, 255, 0, 0, 255, 0, ... 0, 255, 255, 0, 0, 255, 255, 0, 255]) >>> hsv = eve.image_from_values ((1, 6, 3), [ ... 0, 100, 100, 60, 100, 100, 120, 100, 100, ... 180, 100, 100, 240, 100, 100, 300, 100, 100]) >>> eve.rgb_to_hsv (im) >>> eve.compare (im, hsv) 0 Check the converse, from HSV back to RGB. >>> im = eve.image_from_values ((1, 6, 3), [ ... 0, 100, 100, 60, 100, 100, 120, 100, 100, ... 180, 100, 100, 240, 100, 100, 300, 100, 100]) >>> rgb = eve.image_from_values ((1, 6, 3), [ ... 255, 0, 0, 255, 255, 0, 0, 255, 0, ... 0, 255, 255, 0, 0, 255, 255, 0, 255]) >>> eve.hsv_to_rgb (im) >>> eve.compare (im, rgb) 0 Test the conversion from RGB to YIQ. >>> im = eve.image_from_values ((1, 6, 3), [ ... 255, 0, 0, 255, 255, 0, 0, 255, 0, ... 0, 255, 255, 0, 0, 255, 255, 0, 255]) >>> yiq = eve.image_from_values ((1, 6, 3), [ ... 76.24499512, 45.4420166, -7.60223579, 225.92999268, ... 64.52928162, 14.14834595, 149.68499756, 19.08725739, ... 21.75058365, 178.75500488, -45.4420166, 140.96723938, ... 29.06999969, -64.52928162, 119.21665192, 105.31499481, ... -19.08726501, 111.61441803]) >>> eve.rgb_to_yiq (im) >>> eve.compare (im, yiq) 0 Test out the routine to find skin colours. This is built on top of the routine `segment_hsv`, so we're testing them both in this stanza. >>> im = eve.image_from_values ((2,2,3), [ ... 301, 31, 11, 299, 30, 10, 29, 69, 79, 30, 70, 80]) >>> res = eve.image_from_values ((2,2,1), [255, 0, 255, 0]) >>> im = eve.find_skin (im, ishsv=True) >>> eve.compare (im, res) 0 ## Histograms and related operations Let us first test out the histogramming routine with a small number of bins. The routine returns a `numpy` array so we convert that into a list to check. >>> im = eve.image ((5, 4, 2)) >>> im[1,1,1] = 1.0 >>> a, h = eve.histogram (im, bins=8, limits=[0,7]) >>> list (h) [39, 1, 0, 0, 0, 0, 0, 0] As well as the straight histogram, one can also calculate a _cumulative_ histogram in which each value is the sum of that grey level and all darker ones. >>> im = eve.image ((5, 4, 2)) >>> im[1,1,1] = 1.0 >>> a, h = eve.cumulative_histogram (im, bins=8, limits=[0,7]) >>> list (h) [39, 40, 40, 40, 40, 40, 40, 40] Let us see if we can calculate the correct threshold via Otsu's method. The numbers here are identical to those used in my lecture notes. >>> im = eve.image_from_values ((10, 10, 1), [ ... 0, 3, 4, 2, 1, 7, 7, 8, 8, 8, ... 1, 2, 5, 4, 3, 7, 7, 9, 9, 8, ... 0, 1, 4, 5, 4, 8, 9, 9, 8, 8, ... 0, 0, 3, 4, 4, 7, 7, 9, 8, 7, ... 0, 1, 2, 4, 5, 6, 6, 7, 7, 5, ... 1, 1, 2, 5, 5, 5, 5, 6, 7, 4, ... 1, 2, 3, 4, 4, 6, 7, 8, 8, 7, ... 2, 3, 4, 4, 5, 8, 8, 9, 9, 9, ... 0, 1, 2, 4, 4, 6, 7, 8, 9, 8, ... 0, 0, 1, 1, 5, 7, 7, 9, 9, 6]) >>> eve.find_threshold_otsu (im) 4.0 There is an EVE routine for changing the values of pixels according to a look-up table. >>> im = eve.image ((5, 4, 2)) >>> im[1,1,1] = 1.0 >>> eve.lut (im, [1.0, 0.0]) >>> res = eve.image ((5, 4, 2)) >>> eve.set (res, 1.0) >>> res[1,1,1] = 0.0 >>> eve.compare (im, res) 0 EVE also contains a routine to binarize an image at a given threshold. >>> im = eve.image ((5, 4, 2)) >>> eve.set_to_pattern (im) >>> vals = [] >>> for i in range (0, 8): ... vals.append (0) >>> for i in range (8, 40): ... vals.append (255) >>> res = eve.image_from_values ((5, 4, 2), vals, type=numpy.int32) >>> bim = eve.binarize (im, 100) >>> eve.compare (bim, res) 0 Having binarized an image, the usual next step is to label its regions. >>> im = eve.image ((5, 7, 1)) >>> eve.set_region (im, 2, 4, 1, 4, 127.0) >>> res = eve.image (im, type=numpy.int32) >>> eve.set_region (res, 2, 4, 1, 4, 1) >>> reg, nreg = eve.label_regions (im) >>> eve.compare (res, reg) 0 >>> eve.set_region (res, 2, 4, 1, 4, 255.0) >>> reg = eve.labelled_region (reg, 1) >>> eve.compare (res, reg) 0 The slow (pure Python) version of the region labeller should yield identical results. >>> reg, nreg = eve.label_regions_slow (im) >>> eve.compare (res, reg) 0 ## Convolution Set up the image and mask we shall use in some of the tests. >>> im = eve.image ((5, 7, 1)) >>> eve.set_to_pattern (im, xfac=2) >>> mask = eve.image ((3, 3, 1)) >>> eve.set (mask, 1) >>> mask[0,0,0] = mask[2,0,0] = mask[0,2,0] = mask[2,2,0] = 0 Conventional sum-based convolution. >>> res = eve.image_from_values ((5, 7, 1), [ ... 514, 510, 520, 530, 540, 550, 546, ... 514, 510, 520, 530, 540, 550, 546, ... 1014, 1010, 1020, 1030, 1040, 1050, 1046, ... 1514, 1510, 1520, 1530, 1540, 1550, 1546, ... 1514, 1510, 1520, 1530, 1540, 1550, 1546]) >>> conv = eve.convolve (im, mask) >>> eve.compare (conv, res) 0 Using the mean instead of the sum. >>> res = eve.image_from_values ((5, 7, 1), [ ... 514, 510, 520, 530, 540, 550, 546, ... 514, 510, 520, 530, 540, 550, 546, ... 1014, 1010, 1020, 1030, 1040, 1050, 1046, ... 1514, 1510, 1520, 1530, 1540, 1550, 1546, ... 1514, 1510, 1520, 1530, 1540, 1550, 1546]) >>> res /= 9.0 >>> conv = eve.convolve (im, mask, statistic="mean") >>> eve.compare (conv, res, tol=1.0e-5) 0 Using the minimum --- though I'm dubious as to whether this is correct. >>> eve.set (mask, 1) >>> res = eve.image_from_values ((5, 7, 1), [ ... 0, 0, 2, 4, 6, 8, 0, ... 0, 0, 2, 4, 6, 8, 0, ... 100, 100, 102, 104, 106, 108, 100, ... 200, 200, 202, 204, 206, 208, 200, ... 0, 0, 2, 4, 6, 8, 0]) >>> conv = eve.convolve (im, mask, statistic="min") >>> eve.compare (conv, res) 0 Using the maximum. >>> eve.set (mask, 1) >>> res = eve.image_from_values ((5, 7, 1), [ ... 412, 404, 406, 408, 410, 412, 412, ... 212, 204, 206, 208, 210, 212, 212, ... 312, 304, 306, 308, 310, 312, 312, ... 412, 404, 406, 408, 410, 412, 412, ... 412, 404, 406, 408, 410, 412, 412]) >>> conv = eve.convolve (im, mask, statistic="max") >>> eve.compare (conv, res) 0 Using the median. >>> eve.set (mask, 1) >>> res = eve.image_from_values ((5, 7, 1), [ ... 102, 102, 104, 106, 108, 110, 110, ... 102, 102, 104, 106, 108, 110, 110, ... 202, 202, 204, 206, 208, 210, 210, ... 302, 302, 304, 306, 308, 310, 310, ... 302, 302, 304, 306, 308, 310, 310]) >>> conv = eve.convolve (im, mask, statistic="median") >>> eve.compare (conv, res) 0 Following on from simple convolutions, test out the Sobel edge detector. >>> im = eve.image ((10, 7, 1)) >>> eve.set_region (im, 2, 1, 8, 5, 113.0) >>> res = eve.image_from_values ((10, 7, 1), [ ... 0, 0, 0, 0, 0, 0, 0, ... 160, 357, 452, 452, 357, 160, 0, ... 357, 479, 452, 452, 479, 357, 0, ... 452, 452, 0, 0, 452, 452, 0, ... 452, 452, 0, 0, 452, 452, 0, ... 452, 452, 0, 0, 452, 452, 0, ... 452, 452, 0, 0, 452, 452, 0, ... 357, 479, 452, 452, 479, 357, 0, ... 160, 357, 452, 452, 357, 160, 0, ... 0, 0, 0, 0, 0, 0, 0]) >>> im = eve.sobel (im) >>> eve.compare (im, res, tol=0.5) 0 The Canny edge detector. >>> im = eve.image ((10, 7, 1)) >>> eve.set_region (im, 2, 1, 8, 5, 113.0) >>> res = eve.image (im) >>> res[2,1] = res[2,3] = res[2,4] = res[6,1] = res[7,1] = res[7,4] = 255 >>> ce = eve.canny (im, 1.6, 30.0) >>> eve.compare (ce, res, tol=0.5) 0 The Harris corner detector. The positions I expect to obtain are [[60, 80], [60, 240], [180, 80], [180, 240]] so some of the ones produced by `harris` are one pixel out in $y$ or $x$, even though the code in `harris` tries to mitigate its inherent systematic error. >>> ny, nx, nc = 240, 320, 1 >>> im = eve.image ((ny, nx, nc)) >>> ylo = ny / 4 >>> yhi = 3 * ny / 4 >>> xlo = nx / 4 >>> xhi = 3 * nx / 4 >>> eve.set_region (im, ylo, xlo, yhi+1, xhi+1, 127.0) >>> corners = eve.harris (im) >>> for r, y, x in corners: ... print (y, x, end=" ") 60 80 60 241 180 81 180 240 Moravec's corner detector, using the same input image as for Harris. (It isn't as good as Harris.) >>> ny, nx, nc = 240, 320, 1 >>> im = eve.image ((ny, nx, nc)) >>> ylo = ny / 4 >>> yhi = 3 * ny / 4 >>> xlo = nx / 4 >>> xhi = 3 * nx / 4 >>> eve.set_region (im, ylo, xlo, yhi+1, xhi+1, 127.0) >>> eve.moravec (im) [[127.0, 180, 240]] ## Image annotation Let us start by drawing a vertical line in an image. >>> res = eve.image_from_values ((6, 5, 1), [ ... 0, 0, 0, 0, 0, ... 0, 0, 0, 2, 0, ... 0, 0, 0, 2, 0, ... 0, 0, 0, 2, 0, ... 0, 0, 0, 2, 0, ... 0, 0, 0, 0, 0]) >>> im = eve.image ((6, 5, 1)) >>> eve.draw_line (im, 1, 3, 4, 3, 2.0, fast=True) >>> eve.compare (im, res) 0 We'll follow that up with a diagonal line, drawn with aliasing. >>> im = eve.image ((6, 5, 1)) >>> res = eve.image_from_values ((6, 5, 1), [ ... 0, 0, 0, 0, 0, ... 0, 255, 0, 0, 0, ... 0, 147.2, 208.2, 0, 0, ... 0, 0, 208.2, 147.2, 0, ... 0, 0, 0, 255, 0, ... 0, 0, 0, 0, 0]) >>> eve.draw_line (im, 1, 1, 4, 3, 255.0, fast=False) >>> eve.compare (im, res, tol=0.1) 0 Now, let's draw a box. >>> im = eve.image ((6, 5, 1)) >>> res = eve.image_from_values ((6, 5, 1), [ ... 0, 128, 128, 128, 128, ... 0, 128, 255, 255, 128, ... 0, 128, 255, 255, 128, ... 0, 128, 255, 255, 128, ... 0, 128, 128, 128, 128, ... 0, 0, 0, 0, 0]) >>> eve.draw_box (im, 0, 1, 4, 4, border=128, fill=255.0) >>> eve.compare (im, res) 0 Draw a circle, first allowing aliasing. >>> im = eve.image ((6, 6, 1)) >>> res = eve.image_from_values ((6, 6, 1), [ ... 0, 0, 0, 0, 0, 0, ... 0, 0, 255, 255, 255, 0, ... 0, 255, 0, 0, 0, 255, ... 0, 255, 0, 0, 0, 255, ... 0, 255, 0, 0, 0, 255, ... 0, 0, 255, 255, 255, 0]) >>> eve.draw_circle (im, 3, 3, 2, 255.0, fast=True) >>> eve.compare (im, res) 0 Draw another one with anti-aliasing. >>> im = eve.image ((6, 6, 1)) >>> res = eve.image_from_values ((6, 6, 1), [ ... 0, 0, 68.3, 0, 68.3, 0, ... 0, 0, 255, 255, 255, 0, ... 68.3, 255, 236.7, 255, 236.7, 255, ... 0, 255, 255, 0, 255, 255, ... 68.3, 255, 236.7, 255, 236.7, 255, ... 0, 0, 255, 255, 255, 0]) >>> eve.draw_circle (im, 3, 3, 2, 255.0, fast=False) >>> eve.compare (im, res, tol=0.1) 0 Now, draw a polygon. >>> im = eve.image ((20, 20, 1)) >>> res = eve.image_from_values ((20, 20, 1), [ ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, ... 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, ... 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, ... 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, ... 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, ... 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, ... 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, ... 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) >>> epts = [(10.0, 17.0), (16.657395614066075, 12.163118960624633), (14.114496766047314, 4.336881039375369), (5.885503233952689, 4.336881039375368), (3.3426043859339245, 12.16311896062463)] >>> pts = eve.draw_polygon (im, 10, 10, 7, 5, v=1, fast=True) >>> eve.compare (im, res, tol=0.1) 0 >>> eve.compare_lists (eve.flatten_list (pts), eve.flatten_list (epts), ... tol=1.0e-5) 0 And now, a star. >>> im = eve.image ((20, 20, 1)) >>> res = eve.image_from_values ((20, 20, 1), [ ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, ... 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, ... 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) >>> epts = [(10.0, 17.0), (12.057248383023655, 12.831559480312317), (16.657395614066075, 12.163118960624633), (13.328697807033038, 8.918440519687685), (14.114496766047314, 4.336881039375369), (10.0, 6.5), (5.885503233952689, 4.336881039375368), (6.671302192966962, 8.918440519687683), (3.3426043859339245, 12.16311896062463), (7.942751616976343, 12.831559480312315)] >>> pts = eve.draw_star (im, 10, 10, 7, 5, v=1, fast=True) >>> eve.compare (im, res, tol=0.1) 0 >>> eve.compare_lists (eve.flatten_list (pts), eve.flatten_list (epts), ... tol=1.0e-5) 0 Draw a couple of characters. >>> im = eve.image ((20, 20, 1)) >>> res = eve.image_from_values ((20, 20, 1), [ ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, ... 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, ... 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, ... 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, ... 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, ... 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, ... 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, ... 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, ... 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) >>> eve.draw_text (im, 'Ab', 13, 10, 1) >>> eve.compare (im, res, tol=0.1) 0 Do the same only bigger... >>> im = eve.image ((40, 40, 1)) >>> res = eve.image_from_values ((40, 40, 1), [ ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 127, 127, 127, 127, 127, ... 255, 255, 255, 255, 127, 127, 127, 127, 127, 127, 127, 127, ... 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 127, 127, 127, 127, 127, ... 255, 255, 255, 255, 127, 127, 127, 127, 127, 127, 127, 127, ... 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 127, 127, 127, 127, 127, ... 127, 127, 255, 255, 255, 255, 127, 127, 127, 127, 255, 255, ... 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 127, 127, 127, 127, 127, ... 127, 127, 255, 255, 255, 255, 127, 127, 127, 127, 255, 255, ... 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 127, 127, 127, 127, 127, ... 127, 127, 255, 255, 255, 255, 127, 127, 127, 127, 255, 255, ... 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 127, 127, 127, 127, 127, ... 127, 127, 255, 255, 255, 255, 127, 127, 127, 127, 255, 255, ... 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 127, 127, 127, 127, 127, ... 127, 127, 127, 127, 255, 255, 255, 255, 255, 255, 255, 255, ... 127, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 127, 127, 127, 127, 127, ... 127, 127, 127, 127, 255, 255, 255, 255, 255, 255, 255, 255, ... 127, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 127, 127, 127, 127, 127, ... 127, 127, 127, 127, 255, 255, 255, 255, 255, 255, 255, 255, ... 127, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 127, 127, 127, 127, 127, ... 127, 127, 127, 127, 255, 255, 255, 255, 255, 255, 255, 255, ... 127, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 127, 127, 127, 127, 127, ... 127, 127, 127, 127, 127, 127, 255, 255, 255, 255, 127, 127, ... 127, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 127, 127, 127, 127, 127, ... 127, 127, 127, 127, 127, 127, 255, 255, 255, 255, 127, 127, ... 127, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 127, 127, 127, 127, 127, ... 127, 127, 127, 127, 255, 255, 255, 255, 255, 255, 255, 255, ... 127, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 127, 127, 127, 127, 127, ... 127, 127, 127, 127, 255, 255, 255, 255, 255, 255, 255, 255, ... 127, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 127, 127, 127, 127, 127, ... 127, 127, 127, 127, 255, 255, 255, 255, 255, 255, 255, 255, ... 127, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 127, 127, 127, 127, 127, ... 127, 127, 127, 127, 255, 255, 255, 255, 255, 255, 255, 255, ... 127, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 127, 127, 127, 127, 127, ... 127, 127, 255, 255, 255, 255, 127, 127, 127, 127, 255, 255, ... 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 127, 127, 127, 127, 127, ... 127, 127, 255, 255, 255, 255, 127, 127, 127, 127, 255, 255, ... 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 127, 127, 127, 127, 127, ... 127, 127, 255, 255, 255, 255, 127, 127, 127, 127, 255, 255, ... 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 127, 127, 127, 127, 127, ... 127, 127, 255, 255, 255, 255, 127, 127, 127, 127, 255, 255, ... 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 127, 127, 127, 127, 127, ... 255, 255, 255, 255, 127, 127, 127, 127, 127, 127, 127, 127, ... 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 127, 127, 127, 127, 127, ... 255, 255, 255, 255, 127, 127, 127, 127, 127, 127, 127, 127, ... 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 127, 127, 127, 127, 127, ... 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, ... 127, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 127, 127, 127, 127, 127, ... 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, ... 127, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 127, 127, 127, 127, 127, ... 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, ... 127, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 127, 127, 127, 127, 127, ... 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, ... 127, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) >>> eve.draw_text (im, 'X', 39, 20, size=2, bg=127, v=255) >>> eve.compare (im, res, tol=0.1) 0 Check that we can fill an outline. >>> im = eve.image ((6, 5, 1)) >>> res = eve.image_from_values ((6, 5, 1), [ ... 0, 128, 128, 128, 128, ... 0, 128, 120, 120, 128, ... 0, 128, 120, 120, 128, ... 0, 128, 120, 120, 128, ... 0, 128, 128, 128, 128, ... 0, 0, 0, 0, 0]) >>> eve.draw_box (im, 0, 1, 4, 4, border=128, fill=5.0) >>> eve.fill_outline (im, 3, 2, v=120, threshold=10) >>> eve.compare (im, res) 0 Mark some features on an image. >>> im = eve.image ((20, 18, 1)) >>> # y-pos x-pos scale ori >>> locs = [[ 10, 8, 4, 45], ... [ 17, 10, 2, -90]] >>> res = eve.image_from_values ((20, 18, 1), [ ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) >>> eve.mark_features (im, locs, v=1, fast=True, disp=False) >>> eve.compare (im, res) 0 Make sure we can mark some peaks in the right places. >>> im = eve.image ((5, 5, 1)) >>> res = eve.image_from_values ((5, 5, 1), [ ... 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 255, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0]) >>> eve.mark_peaks (im, [[255, 0,1], [6.5, 2,4]], symbol='.') >>> eve.compare (im, res, tol=0.1) 0 Likewise, some positions. >>> im = eve.image ((5, 5, 1)) >>> res = eve.image_from_values ((5, 5, 1), [ ... 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 255, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0]) >>> eve.mark_positions (im, [[0,1], [2,4]], symbol='.') >>> eve.compare (im, res, tol=0.1) 0 ## Hough transform The whole point of doing a Hough transform is that its peaks give the equations of lines; so we need to be sure that the peak-finding routine works as expected first. >>> im = eve.image ((10, 15, 1)) >>> im[6,3] = im[8,5] = 1 >>> eve.find_peaks (im, 0.7) [[1.0, 8, 5], [1.0, 6, 3]] Now, let us look at the straight-line Hough transform itself. >>> ny = 480 >>> nx = 640 >>> nc = 1 >>> im = eve.image ((ny, nx, nc)) >>> eve.draw_line_fast (im, ny//2, nx//4, ny//2, 3*nx//4, 255) >>> peaks, acc, rlist, alist = eve.hough_line (im) >>> epeaks = eve.flatten_list ([[215.0, 89, 100], [170.0, 91, 99], ... [57.0, 97, 97], [57.0, 82, 103], [43.0, 99, 96], [43.0, 80, 104], ... [29.0, 74, 106], [22.0, 67, 108], [16.0, 59, 111], [15.0, 121, 88], ... [15.0, 56, 112], [14.0, 52, 113], [12.0, 46, 115], [11.0, 131, 84], ... [11.0, 43, 116], [11.0, 40, 117]]) >>> eve.compare_lists (eve.flatten_list (peaks), epeaks, 1.0e-5) 0 ## Fourier transform and related operations The FFT routine shifts the origin to the middle of the data array, so let us first ensure that works as expected. >>> im = eve.image ((8,8,3)) >>> eve.set_to_pattern (im) >>> res = numpy.fft.fftshift (im, axes=(-3,-2)) >>> eve.compare_lists (list (res[4,4]), [0.0, 1.0, 2.0], 1.0e-5) 0 >>> eve.compare_lists (list (res[0,0]), [440.0, 441.0, 442.0], 1.0e-5) 0 >>> eve.compare_lists (list (im[0,0]), [0.0, 1.0, 2.0], 1.0e-5) 0 >>> res = numpy.fft.ifftshift (res, axes=(-3,-2)) >>> eve.compare (im, res, 1.0e-5) 0 The Fourier transform of a delta function is a constant. >>> n = 128 >>> im = eve.image ((n, n, 1)) >>> im[n//2,n//2,0] = 1 >>> ft = eve.fourier (im) >>> ft[0,0,0] (1+0j) >>> ft[10,10,0] (1+0j) The Fourier transform of a sine wave is a peak. This test is make more interesting because it yields two peaks of identical height...but rounding errors in the calculation can deliver them in either order. We therefore select both peak locations and sort them before trying to compare them. Note that the peak heights can differ by a little more than in most operations; this need not concern us as the height of the peak is huge! >>> n = 256 >>> im = eve.image ((n, n, 1)) >>> period = n / 4 >>> for x in range (0, n): ... im[:,x,0] = math.sin (float (x) / period * math.pi) * 127.0 >>> before = im[0,0,0] >>> ft = eve.fourier (im) >>> abs (im[0,0,0] - before) < 1.0e-5 True >>> ps = eve.modulus_squared (ft) >>> p = eve.find_peaks (ps, 2.0e-3) >>> peaks = sorted ([[p[0][1], p[0][2]], [p[1][1], p[1][2]]]) >>> epeaks = [128, 126, 128, 130] >>> eve.compare_lists (eve.flatten_list (peaks), epeaks, 1.0e-5) 0 >>> abs (p[0][0] - p[1][0]) < 1.0e-1 True Check that the modulus-square routine works. >>> im = eve.image ((128,128,1), type=numpy.complex64) >>> eve.set (im, (4.0+3.0j)) >>> ps = eve.modulus_squared (im) >>> abs (ps[2,1,0].real - 25.0) < 1.0e-5 True >>> abs (ps[2,1,0].imag) < 1.0e-5 True Check that a forward and reverse transform yields a small residue. >>> im = eve.image ((256,256,1)) >>> eve.thong (im) >>> ft = eve.fourier (im) >>> ft = eve.fourier (ft, forward=False) >>> ft -= im >>> v = ft.max() >>> v = math.sqrt ((v * v.conj()).real) >>> abs (v) < 1.0e-5 True Check that correlation does what we expect. >>> im = eve.image ((256,256,1)) >>> letter = eve.image (im) >>> eve.draw_text (im, 'KofoA', 100, 123) >>> eve.draw_text (im, 'K K K K', 177, 123) >>> eve.draw_text (letter, 'A', 128+7, 129) >>> cor = eve.correlate (im, letter) >>> pos = eve.find_peaks (cor, 1.0e-6) >>> pos[0][1:3] [93, 142] >>> pos[1][1:3] [170, 192] ## Resampling EVE's main resampling routine is `extract`, which can pull out image data with a non-integer sampling size on a rotated grid. >>> im = eve.image ((480, 640, 1)) >>> eve.set_region (im, 50, 10, 400, 20, 128.0) >>> eve.set_region (im, 380, 20, 400, 300, 255.0) >>> reg = eve.extract (im, 10, 10, 400, 20, step=10, angle=math.pi/4) >>> res = eve.image_from_values ((10, 10, 1), [ ... 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, ... 128, 0, 0, 0, 0, 0, 0, 255, 255, 0, ... 0, 128, 0, 0, 0, 0, 255, 255, 0, 0, ... 0, 0, 128, 0, 0, 255, 255, 0, 0, 0, ... 0, 0, 0, 128, 255, 255, 0, 0, 0, 0, ... 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) >>> eve.compare (reg, res, tol=0.00001) 0 Check that the routine for blending the values of pixels does what we expect. >>> im = eve.image ((1,1,1)) >>> im[0,0,0] = 20.3 >>> eve.blend_pixel (im, 0, 0, 6.2, 0.7) >>> abs (im[0,0,0] - 10.43) < 1.0e-2 True Check that we can subsample an image. >>> im = eve.image ((10,9,2)) >>> eve.set_to_pattern (im) >>> res = eve.image_from_values ((5,4,2), [ ... 0, 1, 20, 21, 40, 41, 60, 61, ... 200, 201, 220, 221, 240, 241, 260, 261, ... 400, 401, 420, 421, 440, 441, 460, 461, ... 600, 601, 620, 621, 640, 641, 660, 661, ... 800, 801, 820, 821, 840, 841, 860, 861]) >>> im2 = eve.subsample (im) >>> eve.sizes (im2) (5, 4, 2) >>> eve.compare (im2, res, tol=0.1) 0 >>> im = eve.image ((10,9,2)) >>> eve.set_to_pattern (im) >>> res = eve.image_from_values ((3,3,2), [ ... 0, 1, 30, 31, 60, 61, ... 300, 301, 330, 331, 360, 361, ... 600, 601, 630, 631, 660, 661]) >>> im2 = eve.subsample (im, inc=3) >>> eve.sizes (im2) (3, 3, 2) >>> eve.compare (im2, res, tol=0.1) 0 Check that we can resize an image. >>> im = eve.image ((10,9,1)) >>> eve.set_region (im, 3, 1, 5, 6, 1.0) >>> im2 = eve.resize (im, 4, 7) >>> res = eve.image_from_values ((4, 7, 1), [ ... 0, 0, 0, 0, 0, 0, 0, ... 0, 1, 1, 1, 0.666, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0]) >>> eve.compare (im2, res, tol=0.001) 0 We should be able to insert one image into another. >>> im = eve.image ((8,7,2)) >>> reg = eve.image ((2,3,1)) >>> eve.set (reg, 1.0) >>> eve.insert (im, reg, 4, 3) >>> res = eve.image (im) >>> res[3:5,2:5,0:2] = 1.0 >>> eve.compare (im, res, tol=eve.tiny) 0 ## Annular operations >>> im = eve.image ((10,9,2)) >>> res = eve.image_from_values ((10,9,2), [ ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, ... 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, ... 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) >>> eve.annular_set (im, 1.0, y0=3, x0=7, rlo=3, rhi=5, ... alo=-3.14, ahi=-1.57) >>> eve.compare (res, im, tol=0.1) 0 >>> im = eve.image ((100,90,1)) >>> eve.thong (im) >>> ave = eve.annular_mean (im, y0=70, x0=3, rlo=30, rhi=60, ... alo=0.0, ahi=1.57) >>> abs (ave - 130.311529) < 1.0e-5 True Finally, check the annular profile routine. >>> im = eve.image ((9,9,1)) >>> eve.thong (im) >>> ave = eve.annular_profile (im, y0=5, x0=5, rlo=2, rhi=5, ... alo=-1.5, ahi=0.0) >>> eve.compare_lists (ave, ... [171.91955948, 123.5509552 , 104.47348785, 0.0, 0.0, 0.0], 1.0e-4) 0 ## Miscellaneous effects Sepia. >>> im = eve.image_from_values ((4,3,3), [ ... 255, 0, 0, 0, 255, 0, 0, 0, 255, ... 128, 0, 0, 0, 128, 0, 0, 0, 128, ... 255, 255, 0, 0, 255, 255, 255, 0, 255, ... 0, 0, 0, 255, 255, 255, 128, 128, 128]) >>> res = eve.image_from_values ((4,3,3), [ ... 100, 89, 69, 196, 175, 136, 48, 43, 33, ... 50, 45, 35, 98, 88, 68, 24, 22, 17, ... 255, 255, 206, 244, 218, 170, 148, 132, 103, ... 0, 0, 0, 255, 255, 239, 173, 154, 120]) >>> eve.effect_sepia (im) >>> eve.compare (im, res, tol=0.5) 0 Solarisation. >>> im = eve.image ((4,4,1)) >>> eve.set_to_pattern (im) >>> res = eve.image_from_values ((4,4,1), [ ... 330, 320, 310, 300, ... 230, 220, 210, 200, ... 200, 210, 220, 230, ... 300, 310, 320, 330]) >>> eve.effect_solarize (im) >>> eve.compare (im, res) 0 Streaks. >>> im = eve.image ((6,7,1)) >>> eve.set_region (im, 3, 2, 5, 6, 255.0) >>> res = eve.image_from_values ((6,7,1), [ ... 255, 255, 0, 0, 0, 0, 255, ... 255, 255, 0, 0, 0, 0, 255, ... 255, 255, 0, 0, 0, 0, 255, ... 255, 255, 0, 0, 0, 0, 255, ... 255, 255, 255, 255, 255, 255, 255, ... 255, 255, 255, 255, 255, 255, 255]) >>> im = eve.effect_streaks (im) >>> eve.compare (im, res) 0 Drawing. >>> im = eve.image ((8,5,1)) >>> eve.thong (im) >>> im = eve.effect_drawing (im, blursize=3, opacity=0.9) >>> res = eve.image_from_values ((8, 5, 1), [ ... 255.0, 255.0, 255.0, 255.0, 255.0, 227.7965, ... 218.34535, 220.36691, 218.34535, 227.7965, 226.09521, ... 255.0, 255.0, 255.0, 226.09521, 255.0, ... 255.0, 205.13632, 255.0, 255.0, 255.0, ... 205.13632, 192.0, 205.13632, 255.0, 255.0, ... 255.0, 205.13632, 255.0, 255.0, 226.09521, ... 255.0, 255.0, 255.0, 226.09521, 227.7965, ... 218.34535, 220.36691, 218.34535, 227.7965]) >>> eve.compare (im, res, tol=1.0e-5) 0 ## Operations involving random numbers Operations that involve random numbers are potentially tricky to test. The easiest way to confirm routines work as expected is to use large amounts of data, so we check the routine to add Gaussian noise to an image on one that is $500 \times 500$ pixels in size. >>> im = eve.image ((500,500,1)) >>> eve.set (im, 10.0) >>> eve.add_gaussian_noise (im, seed=0) >>> lo, hi, mean, sd = eve.statistics (im) >>> lo < 9.0 True >>> hi > 11.0 True >>> abs (mean - 10.0) < 1.0e-2 True >>> abs (sd - 1.0) < 1.0e-2 True ## Operations involving external programs Test out the Susan edge-and-corner detector, which we run in corner-detection mode. >>> im = eve.image ((20,20,1)) >>> eve.set_region (im, 4, 8, 16, 12, 255.0) >>> eve.set_region (im, 8, 2, 12, 16, 255.0) >>> sue = eve.susan (im) >>> sue =- im >>> eve.select_pixels_above (im, 1) [[4, 8, 0], [4, 9, 0], [4, 10, 0], [4, 11, 0], [5, 8, 0], [5, 9, 0], [5, 10, 0], [5, 11, 0], [6, 8, 0], [6, 9, 0], [6, 10, 0], [6, 11, 0], [7, 8, 0], [7, 9, 0], [7, 10, 0], [7, 11, 0], [8, 2, 0], [8, 3, 0], [8, 4, 0], [8, 5, 0], [8, 6, 0], [8, 7, 0], [8, 8, 0], [8, 9, 0], [8, 10, 0], [8, 11, 0], [8, 12, 0], [8, 13, 0], [8, 14, 0], [8, 15, 0], [9, 2, 0], [9, 3, 0], [9, 4, 0], [9, 5, 0], [9, 6, 0], [9, 7, 0], [9, 8, 0], [9, 9, 0], [9, 10, 0], [9, 11, 0], [9, 12, 0], [9, 13, 0], [9, 14, 0], [9, 15, 0], [10, 2, 0], [10, 3, 0], [10, 4, 0], [10, 5, 0], [10, 6, 0], [10, 7, 0], [10, 8, 0], [10, 9, 0], [10, 10, 0], [10, 11, 0], [10, 12, 0], [10, 13, 0], [10, 14, 0], [10, 15, 0], [11, 2, 0], [11, 3, 0], [11, 4, 0], [11, 5, 0], [11, 6, 0], [11, 7, 0], [11, 8, 0], [11, 9, 0], [11, 10, 0], [11, 11, 0], [11, 12, 0], [11, 13, 0], [11, 14, 0], [11, 15, 0], [12, 8, 0], [12, 9, 0], [12, 10, 0], [12, 11, 0], [13, 8, 0], [13, 9, 0], [13, 10, 0], [13, 11, 0], [14, 8, 0], [14, 9, 0], [14, 10, 0], [14, 11, 0], [15, 8, 0], [15, 9, 0], [15, 10, 0], [15, 11, 0]]