Mosaic Pictures With Computer Science
Mosaics are a form of art that focuses on assembling small pieces of materials such as tile, porcelain, or glass into a larger pattern, often with the intent of expressing visual messages or a story in addition to being aesthetically appealing. The history of mosaics can be traced back to 3rd millennium BCE in Mesopotamia, where the purpose of mosaics altered from paving marble pieces on the ground to fortify residences to decorating important structures as shown in the Sumerians’ use of mosaic on temple walls. Influenced by this change, in the 5th or 4th century B.C., the Greeks began to establish mosaic as a method of creating art, and in ancient Rome, the use of mosaics blossomed throughout the empire. From countertops to churches, mosaics were gradually integrated into everyday life.
Even today, mosaics are still coveted for their remarkable complexity and creativity. The traditional process of creating mosaic artwork is tedious and requires proficiency in multiple facets of design. Fortunately, with the aid of technology, we can generate mosaic pictures using a much easier approach.
Euclidean distance measures the distance between distinct points in dimensions [Fig. 1]. The less the Euclidean distance between two points, the closer they are in the given dimension. A general .jpg picture can be represented by many 1-pixel by 1-pixel squares, with each square represented by the red, green, and blue value of an integer from 0 to 255. Thus, a .jpg picture whose m-pixels by n-pixels can be easily represented through its RGB value with an array [r1,g1,b1,(r2,g2,b2),…,(rmn,gmn,bmn)], and two pictures’ indexes of similarity can be derived from the Euclidean distance between their representative arrays. Given these mathematic tools, mosaic pictures can be generated using computers.
First, the images (in .jpg format) used as “pieces” for the mosaic picture (referred to as the “mosaic pieces”) are loaded and resized to have the same designed size. Then the actual picture is loaded and has its length and width resized to the nearest multiple of the pieces’ side lengths so that it can be dissected perfectly into pieces (referred to as the “picture pieces”) that have the same dimensions as the mosaic pieces. The picture pieces and mosaic pieces are then expressed in array form and flattened (every element is put into a new array respectively, which signifies that the new array is a one-dimensional array). Each picture piece is labeled from 1 to n, where n is the total amount of picture pieces. A new blank array is created with the dimensions of (number of pieces in a row)*(designed side length for the mosaic pieces) and (number of pieces in a column)*(designed side length for the mosaic pieces). By comparing every picture piece with every mosaic piece, a most similar mosaic piece is assigned to every picture piece. The chosen mosaic pieces are resized and filled into the new blank array in order. When every picture piece has been replaced with a mosaic piece, the array is converted into a .jpg picture and automatically saved.
This algorithm runs fast on personal computers and allows users to control the size of the final picture by giving them the option to establish the desired amount of mosaic pieces in a row and column. Furthermore, it is easy to change the selection of images for the mosaic pieces.
Its applications range from everyday art to attracting publicity in major events. Being able to present details while giving a major idea all through picture gives people lasting impressions; it is important as it lets people practice mosaic art themselves by choosing the pictures they want to use, thus allowing this form of art become common. The algorithm can be improved by making it multi-thread. It currently uses only one core of the CPU.
[Fig. 1]
[Fig. 2]
[Fig. 3]
Appendix (program written in Python)
import cv2import osimport numpy as npimport refrom scipy.spatial.distance import euclideanfrom multiprocessing import Pooldef load_image(length):    #length is the final side length for each loaded image    piece_names=os.listdir('imgStorage/'+pieceSet)    loaded=[]    for individualPiece in piece_names:        if not re.search(".jpg",individualPiece,re.I):  #Check for .jpg format            continue            #if not .jpg, do not process        try:            pieceImg=cv2.imread('imgStorage/'+pieceSet+'/'+individualPiece)            pieceImg=cv2.resize(pieceImg,(length,length),interpolation=cv2.INTER_CUBIC)            loaded.append(np.array(pieceImg))        except Exception as exc:            print(individualPiece+'  '+str(exc))  #print exception for certain file    return np.array(loaded,dtype=np.uint8)def get_new_dimensions(picture_dimensions,sideLength):    picture_dimensions[0]=int(picture_dimensions[0]/sideLength)*sideLength    picture_dimensions[1]=int(picture_dimensions[1]/sideLength)*sideLength    return picture_dimensionsdef get_distance(imgA,imgB):    arrayA=imgA.flatten()    arrayB=imgB.flatten()    distance=euclidean(arrayA,arrayB)    return distancedef get_minD_Index(compare_piece):    currentMin=get_distance(compare_piece,img_pieces[0])    currentMinIndex=0    for j in range(1,len(img_pieces)):        if get_distance(compare_piece,img_pieces[j])<currentMin:            currentMin=get_distance(compare_piece,img_pieces[j])            currentMinIndex=j    return currentMinIndexdef replace_Piece(i):    picture_section=picture[int((i//piece_col)*sideL):int((i//piece_col+1)*sideL),int((i%piece_col)*sideL):int((i%piece_col+1)*sideL),:]    newPicture[int((i//piece_col)*pieceL):int((i//piece_col+1)*pieceL),int((i%piece_col)*pieceL):int((i%piece_col+1)*pieceL),:]=usePiece[get_minD_Index(picture_section)]if __name__ == '__main__':    pieceSet=str(input('choose the set of pieces: '))    sideL=int(input('insert side length for disecting the picture: '))    pieceL=int(input('insert side length for puzzle\'s piece: '))    img_pieces=load_image(sideL)    usePiece=load_image(pieceL)    print('successfully loaded {} images for mosaic piece'.format(len(usePiece)))    originalName=input('insert the picture\'s name: ')    global picture    picture=cv2.imread('Original/'+originalName+'.jpg')    old_picture_dimensions=list(picture.shape)    print('old dimensions of the picture↓')    print(old_picture_dimensions)    new_picture_dimensions=get_new_dimensions(old_picture_dimensions,sideL)    #make dimensions the nearest multiple of sideL    print('modified dimensions of the picture↓')    print(new_picture_dimensions)    picture=cv2.resize(picture,(new_picture_dimensions[1],new_picture_dimensions[0]),interpolation=cv2.INTER_CUBIC)    #resize the picture to its new dimensions    piece_row=new_picture_dimensions[0]//sideL    piece_col=new_picture_dimensions[1]//sideL    newPicture=np.zeros([int(piece_row*pieceL),int(piece_col*pieceL),3],dtype=np.uint8)    print('final dimensions of the picture↓')    print(list(newPicture.shape))    for i in range(piece_row*piece_col):        replace_Piece(i)    cv2.imwrite(originalName+'-mosaiced.jpg',newPicture,[int(cv2.IMWRITE_JPEG_QUALITY),90])    end=input('Complete!')
![[Fig. 1]](https://images.squarespace-cdn.com/content/v1/5c93a862b2cf79b120ed5401/1572331691227-YVRW99AIRL43DH0FX8CV/Screen+Shot+2019-10-28+at+11.48.02+PM.png) 
            ![[Fig. 2]](https://images.squarespace-cdn.com/content/v1/5c93a862b2cf79b120ed5401/1572331231600-LQ8EEZGRPHM6EVYSETDV/Screen+Shot+2019-10-28+at+11.36.15+PM.png) 
            ![[Fig. 3]](https://images.squarespace-cdn.com/content/v1/5c93a862b2cf79b120ed5401/1572331471878-KYR7IJIL8Q2BRBWEMUTJ/Screen+Shot+2019-10-28+at+11.36.06+PM.png)