<jupyter_start><jupyter_text>2. Index assetsIn order to build a mosaic, we want to replace each image part with a matching source picture (a patch). We will run the search algorithm to find the best matches.To make search fast, we will store preprocessed sources together with their feature vectors. More precisely, we will store:  - a resized version of the original  - result of applying Sobel filter to the resized image  - image description in the form of CSV file entry  The `index_images` function from the `mosaic_mager.index_assets` moduleis responsible for indexing sources. It uses `ImageProcessor` class from the `mosaic_maker.basic_processing.image_processor` module that will resize and create a Sobel version of the input. After these operations, both results are fed to the `Patch` class from the `mosaic_maker.patch.patch` module that will be responsible for creating a description of the input images.The `Patch` class will also be used in mosaic creation. One could consider embedding Sobel operators in the `Patch` itself, but in the case of mosaic composing, we will want to apply them for the whole source image, not only currently processed part. This way, we'll have better values for patches' borders.In this chapter, we will focus on the `ImageProcessor` implementation. `Patch`,in its current version, will return dummy feature vectors, but we will feed it with properly rescaled and transformed images that will be stored in the `assets` directory.Image processing will consist of three steps:  1. Cropping image to the square shape - patches are square, so we will  use only the central part fo the images leaving out the margins  2. Applying Sobel filters  3. Resizing cropped original and its Sobel version.<jupyter_code>from config import IMAGES_SET, PATCH_SIZE
from mosaic_maker.index_assets import index_images
index_images(IMAGES_SET, PATCH_SIZE)<jupyter_output>PROCESSING FILES:
  > 0068.jpg  DONE<jupyter_text>After the running line above, the `indexed-sources` directory should appear in `assets`. In this directory, you will find another directory named after source images set name. It will contain processed images and a CSV file.As `ImageProcessor` contains only dummy implementation, processed images will be the original images, and CSV will only contain empty lines with filenames in the first column. Let's work on the image processor. We willuse the target image generated in the previous chapter as our test input.<jupyter_code>import cv2
from matplotlib import pyplot as plt
from config import PROJECT_ROOT
image_path = PROJECT_ROOT / 'assets/test-target.jpg'
print(PROJECT_ROOT / 'assets/test-target.jpg')
test_image = cv2.imread(image_path.as_posix())
plt.imshow(cv2.cvtColor(test_image, cv2.COLOR_BGR2RGB))<jupyter_output>/Users/pawelgolab/IdeaProjects/mosaic-maker-opencv-python/assets/test-target.jpg<jupyter_text>Let's create an `ImageProcessor` class instance for it.For now, we will focus on the two fields of `ImageProcessor` class:`cropped_image` and `sobel_magnitude_image`.<jupyter_code>from mosaic_maker.basic_processing.image_processor import ImageProcessor
processed_test = ImageProcessor('test', test_image, PATCH_SIZE)

_, grid = plt.subplots(1, 2)
grid[0].imshow(cv2.cvtColor(processed_test.cropped_image, cv2.COLOR_BGR2RGB))
grid[1].imshow(processed_test.sobel_magnitude_image, cmap='gray')<jupyter_output><empty_output><jupyter_text>As no of the functions is implemented yet, you should see two copies of the original image above. The right one will have wrong colors but we can leaveit this way - after processing image will be in grayscale and will be displayed correctly.Let's start with cropping the image to the center square.Use basic `Numpy` indexing and a `shape` field to achieve this target. You will find a description of the needed operators in the `Numpy`[quickstart tutorial](https://docs.scipy.org/doc/numpy/user/quickstart.html).You can wokr on `test_image` in this notebook.After finding proper algorithm, modify `_crop_to_square` method of `ImageProcessor` to make it work within the class.<jupyter_code>test_image_copy = test_image.copy() 

# do some sample operations on test image copy here

plt.imshow(cv2.cvtColor(test_image_copy, cv2.COLOR_BGR2RGB))<jupyter_output><empty_output><jupyter_text>After fixing `crop_to_square` method block below should create two croppedimages.<jupyter_code>processed_test = ImageProcessor('test', test_image, PATCH_SIZE)

_, grid = plt.subplots(1, 2)
grid[0].imshow(cv2.cvtColor(processed_test.cropped_image, cv2.COLOR_BGR2RGB))
grid[1].imshow(processed_test.sobel_magnitude_image, cmap='gray')<jupyter_output><empty_output><jupyter_text>Now let's work on Sobel filters.Applying Sobel filters will be more sophisticated than cropping images. You will have to perform the following steps:  - Convert image to grayscale and blur the result - read   [changing colorspaces tutorial](https://docs.opencv.org/master/df/d9d/tutorial_py_colorspaces.html)  and   [smoothing images tutorial](https://docs.opencv.org/master/d4/d13/tutorial_py_filtering.html)  - Calculate gradients - read [image gradients tutorial](https://docs.opencv.org/master/d5/d0f/tutorial_py_gradients.html)  to find instructions for building `x` and `y` Sobel images  - process gradients by applying   [`convertScaleAbs`](https://docs.opencv.org/4.2.0/d2/de8/group__core__array.htmlga3460e9c9f37b563ab9dd550c4d8c4e7d)  function to remove signs and then combine results using    [`addWeighted`](https://docs.opencv.org/4.2.0/d2/de8/group__core__array.htmlgafafb2513349db3bcff51f54ee5592a19)  - to remove noises and unimportant edges, threshold result - you can read  about this operation in the [image thresholding tutorial](https://docs.opencv.org/master/d7/d4d/tutorial_py_thresholding.html)You can work on the code block below and then apply results to the`calculate_sobel_magnitude_image` method.<jupyter_code>test_image_copy = test_image.copy() 

# do some sample operations on test image copy here

plt.imshow(cv2.cvtColor(test_image_copy, cv2.COLOR_BGR2RGB))<jupyter_output><empty_output><jupyter_text>After applying all changes, you should see two different images below: one withthe cropped image and one with edges.<jupyter_code>processed_test = ImageProcessor('test', test_image, PATCH_SIZE)

_, grid = plt.subplots(1, 2)
grid[0].imshow(cv2.cvtColor(processed_test.cropped_image, cv2.COLOR_BGR2RGB))
grid[1].imshow(processed_test.sobel_magnitude_image, cmap='gray')<jupyter_output><empty_output><jupyter_text>We can now run `index_images` function again and check the resultsin the the `assets` directory.<jupyter_code>index_images(IMAGES_SET, PATCH_SIZE)<jupyter_output>PROCESSING FILES:
  > 0068.jpg  DONE
{'fraction_non_alphanumeric': 0.07473150357995227, 'fraction_numerical': 0.014767303102625298, 'mean_word_length': 6.072784810126582, 'pattern_counts': {'":': 0, '<': 30, '<?xml version=': 0, '>': 32, 'https://': 7, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '8', 'dir': 'jupyter-structured-clean-dedup', 'id': '29523', 'license': 'MIT', 'n_tokens_mistral': 2085, 'n_tokens_neox': 1983, 'n_words': 697, 'path': 'notebooks/2-index-assets.ipynb', 'repo_name': 'pgolab/mosaic-maker-opencv-python', 'size': '6704'}