diff --git a/.github/workflows/python-format.yml b/.github/workflows/python-format.yml index 5fb83a0d..0eac2193 100644 --- a/.github/workflows/python-format.yml +++ b/.github/workflows/python-format.yml @@ -30,4 +30,4 @@ jobs: black_args: "--line-length 79 --exclude='1_beginner/chapter1/examples/error.py'" # same max line length as flake8 flake8_args: "--max-line-length=88 --ignore=E203,W503 --exclude=1_beginner/chapter1/examples/error.py" # prevent conflicts with black auto_fix: true # auto commit style fixes - + \ No newline at end of file diff --git a/1_beginner/chapter5/practice/alternating.py b/1_beginner/chapter5/practice/alternating.py index a57c1dde..0fe44abc 100644 --- a/1_beginner/chapter5/practice/alternating.py +++ b/1_beginner/chapter5/practice/alternating.py @@ -1,17 +1,12 @@ """ Alternating - -Ask the user for an integer. The print the numbers from 1 to that number, -but alternating in sign. For example, if the input was 5, what would be printed -is 1, -1, 2, -2, 3, -3, 4, -4, 5. (Note, DO NOT include the last negative -number). - -Do this with a for loop +Ask the user for a positive integer. Then print the numbers from 1 +to that number, but alternating in sign. For example, if the input +was 5, what would be printed is 1, -1, 2, -2, 3, -3, 4, -4, 5. +(Note, DO NOT include the last negative number). +Do this with a for loop and then with a while loop. """ -# Write code here. - -number = int(input("Enter Number Here: ")) - +# Write code here # Now try it with a while loop diff --git a/1_beginner/chapter5/solutions/alternating.py b/1_beginner/chapter5/solutions/alternating.py new file mode 100644 index 00000000..de8f197d --- /dev/null +++ b/1_beginner/chapter5/solutions/alternating.py @@ -0,0 +1,27 @@ +""" +Alternating +Ask the user for a positive integer. Then print the numbers from 1 +to that number, but alternating in sign. For example, if the input +was 5, what would be printed is 1, -1, 2, -2, 3, -3, 4, -4, 5. +(Note, DO NOT include the last negative number). +Do this with a for loop and then with a while loop. +""" + +# for loop solution +number = int(input("Enter number here: ")) +for num in range(1, number + 1): + if num == number: + print(num) + else: + print(num) + print(-num) + + +# while loop solution +number = int(input("Enter number here: ")) +current_num = 1 +while current_num < number: + print(current_num) + print(-current_num) + current_num += 1 +print(current_num) diff --git a/2_intermediate/chapter10/practice/img_avg.py b/2_intermediate/chapter10/practice/img_avg.py index dc9de796..2b71c3b3 100644 --- a/2_intermediate/chapter10/practice/img_avg.py +++ b/2_intermediate/chapter10/practice/img_avg.py @@ -1,50 +1,83 @@ """ Image Average -Here is the challenge problem for 2D loops: -Images are often represented as 3D arrays, -where the rows and columns are the pixels in the image, -and each pixel has an RGB (red, green, blue) value -which determines the color of the pixel. +Here is the challenge problem for nested loops: +Images are often represented as 3D lists. +The outer list is the entire image. +The 1st level inner list is a row of pixels. +The 2nd level inner list is the RGB values for that pixel. +RGB (red, green, blue) values determine the color of the pixel. The interesting thing is that we can iterate over images. -The challenge is, given an image, create a program that +The challenge is: given an image, create a program that will return a different image where each pixel is the average of the pixels surrounding it in the original image. -The neighbors of an image are all the pixels that surround it, -1 on each side, and 4 on the diagonals, for 8 in total. Each -pixel doesn't necessarily have 8 neighbors, though (think about why). - -The code to grab an image from the internet and make it -into an array is given to you. The code also displays the new image -you create in the end. - -NOTE: The image is 3 dimensional because each pixel has RGB values. To find the average value of all of a pixels neighbors, you must -change the average of the red value to the red value, blue to blue, etc. +calculate the average of the red values, blue values, and green values. For example, if the neighbors of a pixel with value [1, 2, 3] were [20, 30, 40] and [10, 120, 30], the new pixel that would replace the -original one would be [15, 75, 35] +original one would be [15, 75, 35] (since the average of 20 and 10 is 15, +the average of 30 and 120 is 75, and the average of 40 and 30 is 35). + +EXAMPLE: An image with 9 pixels may look like: +[ + [ + [31, 41, 42], [51, 1, 101], [24, 141, 33] + ], + + [ + [50, 21, 28], [31, 49, 201], [90, 54, 33] + ], + + [ + [12, 81, 3], [22, 8, 91], [101, 141, 132] + ] +] + +HINT: Don't forget that a pixel may have varying amount of neighboring +pixels. A pixel at the edge, for example, has 3 neighboring pixels while +a pixel at the center of the image has 8 neighboring pixels (one on each +of its 4 sides, and then one at each of its 4 corners). """ +# Import libraries needed to run the program +# Before importing the libraries, you must have them installed. +# This problem requires the following libraries: +# pillow, requests, numpy, and matplotlib +# If you don't already have them installed, open your command prompt or terminal +# and please do +# this: pip install -U (library) (any other libraries, each separated by a space) +# ex: pip install -U numpy matplotlib requests pillow +# Note: on some windows machines, you may need to +# do: py -m pip install -U (library) (any other libraries, each separated by a space) + from PIL import Image import requests import numpy import matplotlib.pyplot as plt -url = "https://images.dog.ceo/breeds/waterdog-spanish/20180723_185544.jpg" -img = numpy.array(Image.open(requests.get(url, stream=True).raw)).tolist() -newimg = img -transpose = numpy.transpose(img) +# Code that grabs the image from the internet and makes it into an array +IMAGE_URL = ( + "https://images.dog.ceo/breeds/waterdog-spanish/20180723_185544.jpg" +) +img = numpy.array( + Image.open(requests.get(IMAGE_URL, stream=True).raw) +).tolist() + +# create newimg as an empty list so that we'll know if something went wrong +# ie. if we try to display it and the function didn't run, we'd get an +# invalid shape error +newimg = [[[] for column in row] for row in img] +# Code that displays the original image +print("now displaying the original image") plt.imshow(img) plt.show() -# write code to create newimg here +# Write code to create newimg here +# Code that displays the new image at the end +print("now displaying the new image") plt.imshow(newimg) plt.show() - -plt.imshow(transpose) -plt.show() diff --git a/2_intermediate/chapter10/solutions/img_avg.py b/2_intermediate/chapter10/solutions/img_avg.py index 815ab8ea..66077ed6 100644 --- a/2_intermediate/chapter10/solutions/img_avg.py +++ b/2_intermediate/chapter10/solutions/img_avg.py @@ -1,95 +1,162 @@ """ Image Average -Here is the challenge problem for 2D loops: -Images are often represented as 3D arrays, -where the rows and columns are the pixels in the image, -and each pixel has an RGB (red, green, blue) value -which determines the color of the pixel. +Here is the challenge problem for nested loops: +Images are often represented as 3D lists. +The outer list is the entire image. +The 1st level inner list is a row of pixels. +The 2nd level inner list is the RGB values for that pixel. +RGB (red, green, blue) values determine the color of the pixel. The interesting thing is that we can iterate over images. -The challenge is, given an image, create a program that +The challenge is: given an image, create a program that will return a different image where each pixel is the average of the pixels surrounding it in the original image. -The neighbors of an image are all the pixels that surround it, -1 on each side, and 4 on the diagonals, for 8 in total. Each -pixel doesn't necessarily have 8 neighbors, though (think about why). - -The code to grab an image from the internet and make it -into an array is given to you. The code also displays the new image -you create in the end. - -NOTE: The image is 3 dimensional because each pixel has RGB values. To find the average value of all of a pixels neighbors, you must -change the average of the red value to the red value, blue to blue, etc. +calculate the average of the red values, blue values, and green values. For example, if the neighbors of a pixel with value [1, 2, 3] were [20, 30, 40] and [10, 120, 30], the new pixel that would replace the -original one would be [15, 75, 35] +original one would be [15, 75, 35] (since the average of 20 and 10 is 15, +the average of 30 and 120 is 75, and the average of 40 and 30 is 35). + +EXAMPLE: An image with 9 pixels may look like: +[ + [ + [31, 41, 42], [51, 1, 101], [24, 141, 33] + ], + + [ + [50, 21, 28], [31, 49, 201], [90, 54, 33] + ], + + [ + [12, 81, 3], [22, 8, 91], [101, 141, 132] + ] +] + +HINT: Don't forget that a pixel may have varying amount of neighboring +pixels. A pixel at the edge, for example, has 3 neighboring pixels while +a pixel at the center of the image has 8 neighboring pixels (one on each +of its 4 sides, and then one at each of its 4 corners). """ +# Import libraries needed to run the program +# Before importing the libraries, you must have them installed. +# This problem requires the following libraries: +# pillow, requests, numpy, and matplotlib +# If you don't already have them installed, open your command prompt or terminal +# and please do +# this: pip install -U (library) (any other libraries, each separated by a space) +# ex: pip install -U numpy matplotlib requests pillow +# Note: on some windows machines, you may need to +# do: py -m pip install -U (library) (any other libraries, each separated by a space) + + from PIL import Image import requests import numpy import matplotlib.pyplot as plt -url = "https://images.dog.ceo/breeds/waterdog-spanish/20180723_185544.jpg" -img = numpy.array(Image.open(requests.get(url, stream=True).raw)) -newimg = img -transpose = numpy.transpose(img) +# Code that grabs the image from the internet and makes it into an array +IMAGE_URL = ( + "https://images.dog.ceo/breeds/waterdog-spanish/20180723_185544.jpg" +) +img = numpy.array( + Image.open(requests.get(IMAGE_URL, stream=True).raw) +).tolist() + +# create newimg as an empty list so that we'll know if something went wrong +# ie. if we try to display it and the function didn't run, we'd get an +# invalid shape error +newimg = [[[] for column in row] for row in img] + +# Code that displays the original image +print("now displaying the original image") +plt.imshow(img) +plt.show() -# write code to create newimg here -def solution1(): +def distort(original_image, new_image): """ - Iterating over the image here. i is a variable from - 0 to the width of the image. - j is a variable that ranges from 0 to the height of the image. - i is associated with values + Modifies new_image so that each pixel in new_image + will be the average of the surrounding + DISTORTION_RADIUS pixels. + DISTORTION_RADIUS can be changed for more/less distortion. + Arguments: + original_image (list or tuple) - the reference image. + new_image (list) - the image to modify. """ - for i in range(len(img)): - for j in range(len(img[0])): - x_n = [0] - y_n = [0] - - if i == 0: - x_n.append(1) - elif i == len(img) - 1: - x_n.append(-1) - else: - x_n.append(1) - x_n.append(-1) - - if j == 0: - y_n.append(1) - elif j == len(img[0]) - 1: - y_n.append(-1) - else: - y_n.append(1) - y_n.append(-1) - - r_avg = -1 * img[i][j][0] - g_avg = -1 * img[i][j][1] - b_avg = -1 * img[i][j][2] - c = -1 - - for x in x_n: - for y in y_n: - r_avg += img[i + x][j + y][0] - g_avg += img[i + x][j + y][1] - b_avg += img[i + x][j + y][2] - c += 1 - r_avg = r_avg / c - g_avg = g_avg / c - b_avg = b_avg / c - - newimg[i][j] = [r_avg, g_avg, b_avg] - - -solution1() - + DISTORTION_RADIUS = 1 # this should be a positive integer + # Note that each increase of DISTORTION_RADIUS increases + # run time amazingly. Slower PC's should stick to values like + # 1 or 2 for DISTORTION_RADIUS + + for row in range(len(original_image)): + for column in range(len(original_image[0])): + # we set these to empty lists because the for loops + # will iterate through all valid relative indexes + # (including 0) and append them to these lists. + x_relative_indexes = [] + y_relative_indexes = [] + + # handle y relative indexes + # +1 to DISTORTION_RADIUS because stop is exclusive + for relative_y in range(-DISTORTION_RADIUS, DISTORTION_RADIUS + 1): + if ( + row + relative_y < 0 + or row + relative_y > len(original_image) - 1 + ): + # ignore relative indexes that are out of range of the + # original image + continue + # if it isn't out of range, it's valid and should be appended + y_relative_indexes.append(relative_y) + + # handle x relative indexes + # +1 to DISTORTION_RADIUS because stop is exclusive + for relative_x in range(-DISTORTION_RADIUS, DISTORTION_RADIUS + 1): + if ( + column + relative_x < 0 + or column + relative_x > len(original_image[0]) - 1 + ): + # ignore relative indexes that are out of range of the + # original image + continue + # if it isn't out of range, it's valid and should be appended + x_relative_indexes.append(relative_x) + + # at this point, x_relative_indexes and y_relative_indexes are + # complete, so now we use them. + r_total = g_total = b_total = counter = 0 # initialize variables + for x in x_relative_indexes: + for y in y_relative_indexes: + # since images are 'rgb': + # red is the first val + r_total += original_image[row + y][column + x][0] + + # green is the second val + g_total += original_image[row + y][column + x][1] + + # blue is third val + b_total += original_image[row + y][column + x][2] + + counter += 1 + + # round because images don't deal w/ floats, only integers + r_avg = round(r_total / counter) + g_avg = round(g_total / counter) + b_avg = round(b_total / counter) + + # update the pixel in newimg to match the average of its + # surrounding pixels + new_image[row][column] = [r_avg, g_avg, b_avg] + + +print("now modifying file. Depending on your pc, this may take a while.") +distort(img, newimg) + +# Code that displays the new image at the end +print("now displaying the new image") plt.imshow(newimg) plt.show() - -plt.imshow(transpose) -plt.show()