{"id":57,"date":"2024-11-08T14:06:42","date_gmt":"2024-11-08T14:06:42","guid":{"rendered":"https:\/\/theroyalscode.com\/students\/l_rankins\/?p=57"},"modified":"2024-11-08T14:06:42","modified_gmt":"2024-11-08T14:06:42","slug":"blog-four-maddness-is-eternal","status":"publish","type":"post","link":"https:\/\/theroyalscode.com\/students\/l_rankins\/2024\/11\/08\/blog-four-maddness-is-eternal\/","title":{"rendered":"BLOG FOUR: MADDNESS IS ETERNAL"},"content":{"rendered":"\n<p>I made a Photomosaic program with a book tutorial heres the code with proper credit<\/p>\n\n\n\n<p>&#8220;&#8221;&#8221;<\/p>\n\n\n\n<p>photomosaic.py<\/p>\n\n\n\n<p>Creates a photomosaic given a target image and a folder of input images<\/p>\n\n\n\n<p>Author: Mahesh Venkitachalam<\/p>\n\n\n\n<p>&#8220;&#8221;&#8221;<\/p>\n\n\n\n<p>import sys, os, random, argparse<\/p>\n\n\n\n<p>from PIL import Image<\/p>\n\n\n\n<p>import imghdr<\/p>\n\n\n\n<p>import numpy as np<\/p>\n\n\n\n<p><em>def<\/em> getAverageRGBOld(<em>image<\/em>):<\/p>\n\n\n\n<p>&nbsp; &#8220;&#8221;&#8221;<\/p>\n\n\n\n<p>&nbsp; Given PIL Image, return average value of color as (r, g, b)<\/p>\n\n\n\n<p>&nbsp; &#8220;&#8221;&#8221;<\/p>\n\n\n\n<p>&nbsp; # no. of pixels in image<\/p>\n\n\n\n<p>&nbsp; npixels = <em>image<\/em>.size[0]*<em>image<\/em>.size[1]<\/p>\n\n\n\n<p>&nbsp; # get colors as [(cnt1, (r1, g1, b1)), &#8230;]<\/p>\n\n\n\n<p>&nbsp; cols = <em>image<\/em>.getcolors(npixels)<\/p>\n\n\n\n<p>&nbsp; # get [(c1*r1, c1*g1, c1*g2),&#8230;]<\/p>\n\n\n\n<p>&nbsp; sumRGB = [(x[0]*x[1][0], x[0]*x[1][1], x[0]*x[1][2]) for x in cols]<\/p>\n\n\n\n<p>&nbsp; # calculate (sum(ci*ri)\/np, sum(ci*gi)\/np, sum(ci*bi)\/np)<\/p>\n\n\n\n<p>&nbsp; # the zip gives us [(c1*r1, c2*r2, ..), (c1*g1, c1*g2,&#8230;)&#8230;]<\/p>\n\n\n\n<p>&nbsp; avg = tuple([int(sum(x)\/npixels) for x in zip(*sumRGB)])<\/p>\n\n\n\n<p>&nbsp; return avg<\/p>\n\n\n\n<p><em>def<\/em> getAverageRGB(<em>image<\/em>):<\/p>\n\n\n\n<p>&nbsp; &#8220;&#8221;&#8221;<\/p>\n\n\n\n<p>&nbsp; Given PIL Image, return average value of color as (r, g, b)<\/p>\n\n\n\n<p>&nbsp; &#8220;&#8221;&#8221;<\/p>\n\n\n\n<p>&nbsp; # get image as numpy array<\/p>\n\n\n\n<p>&nbsp; im = np.array(<em>image<\/em>)<\/p>\n\n\n\n<p>&nbsp; # get shape<\/p>\n\n\n\n<p>&nbsp; w,h,d = im.shape<\/p>\n\n\n\n<p>&nbsp; # get average<\/p>\n\n\n\n<p>&nbsp; return tuple(np.average(im.reshape(w*h, d), <em>axis<\/em>=0))<\/p>\n\n\n\n<p><em>def<\/em> splitImage(<em>image<\/em>, <em>size<\/em>):<\/p>\n\n\n\n<p>&nbsp; &#8220;&#8221;&#8221;<\/p>\n\n\n\n<p>&nbsp; Given Image and dims (rows, cols) returns an m*n list of Images<\/p>\n\n\n\n<p>&nbsp; &#8220;&#8221;&#8221;<\/p>\n\n\n\n<p>&nbsp; W, H = <em>image<\/em>.size[0], <em>image<\/em>.size[1]<\/p>\n\n\n\n<p>&nbsp; m, n = <em>size<\/em><\/p>\n\n\n\n<p>&nbsp; w, h = int(W\/n), int(H\/m)<\/p>\n\n\n\n<p>&nbsp; # image list<\/p>\n\n\n\n<p>&nbsp; imgs = []<\/p>\n\n\n\n<p>&nbsp; # generate list of dimensions<\/p>\n\n\n\n<p>&nbsp; for j in range(m):<\/p>\n\n\n\n<p>&nbsp; &nbsp; for i in range(n):<\/p>\n\n\n\n<p>&nbsp; &nbsp; &nbsp; # append cropped image<\/p>\n\n\n\n<p>&nbsp; &nbsp; &nbsp; imgs.append(<em>image<\/em>.crop((i*w, j*h, (i+1)*w, (j+1)*h)))<\/p>\n\n\n\n<p>&nbsp; return imgs<\/p>\n\n\n\n<p><em>def<\/em> getImages(<em>imageDir<\/em>):<\/p>\n\n\n\n<p>&nbsp; &#8220;&#8221;&#8221;<\/p>\n\n\n\n<p>&nbsp; given a directory of images, return a list of Images<\/p>\n\n\n\n<p>&nbsp; &#8220;&#8221;&#8221;<\/p>\n\n\n\n<p>&nbsp; files = os.listdir(<em>imageDir<\/em>)<\/p>\n\n\n\n<p>&nbsp; images = []<\/p>\n\n\n\n<p>&nbsp; for file in files:<\/p>\n\n\n\n<p>&nbsp; &nbsp; filePath = os.path.abspath(os.path.join(<em>imageDir<\/em>, file))<\/p>\n\n\n\n<p>&nbsp; &nbsp; try:<\/p>\n\n\n\n<p>&nbsp; &nbsp; &nbsp; # explicit load so we don&#8217;t run into resource crunch<\/p>\n\n\n\n<p>&nbsp; &nbsp; &nbsp; fp = open(filePath, &#8220;rb&#8221;)<\/p>\n\n\n\n<p>&nbsp; &nbsp; &nbsp; im = Image.open(fp)<\/p>\n\n\n\n<p>&nbsp; &nbsp; &nbsp; images.append(im)<\/p>\n\n\n\n<p>&nbsp; &nbsp; &nbsp; # force loading image data from file<\/p>\n\n\n\n<p>&nbsp; &nbsp; &nbsp; im.load()<\/p>\n\n\n\n<p>&nbsp; &nbsp; &nbsp; # close the file<\/p>\n\n\n\n<p>&nbsp; &nbsp; &nbsp; fp.close()<\/p>\n\n\n\n<p>&nbsp; &nbsp; except:<\/p>\n\n\n\n<p>&nbsp; &nbsp; &nbsp; # skip<\/p>\n\n\n\n<p>&nbsp; &nbsp; &nbsp; print(&#8220;Invalid image: %s&#8221; % (filePath,))<\/p>\n\n\n\n<p>&nbsp; return images<\/p>\n\n\n\n<p><em>def<\/em> getImageFilenames(<em>imageDir<\/em>):<\/p>\n\n\n\n<p>&nbsp; &#8220;&#8221;&#8221;<\/p>\n\n\n\n<p>&nbsp; given a directory of images, return a list of Image file names<\/p>\n\n\n\n<p>&nbsp; &#8220;&#8221;&#8221;<\/p>\n\n\n\n<p>&nbsp; files = os.listdir(<em>imageDir<\/em>)<\/p>\n\n\n\n<p>&nbsp; filenames = []<\/p>\n\n\n\n<p>&nbsp; for file in files:<\/p>\n\n\n\n<p>&nbsp; &nbsp; filePath = os.path.abspath(os.path.join(<em>imageDir<\/em>, file))<\/p>\n\n\n\n<p>&nbsp; &nbsp; try:<\/p>\n\n\n\n<p>&nbsp; &nbsp; &nbsp; imgType = imghdr.what(filePath)<\/p>\n\n\n\n<p>&nbsp; &nbsp; &nbsp; if imgType:<\/p>\n\n\n\n<p>&nbsp; &nbsp; &nbsp; &nbsp; filenames.append(filePath)<\/p>\n\n\n\n<p>&nbsp; &nbsp; except:<\/p>\n\n\n\n<p>&nbsp; &nbsp; &nbsp; # skip<\/p>\n\n\n\n<p>&nbsp; &nbsp; &nbsp; print(&#8220;Invalid image: %s&#8221; % (filePath,))<\/p>\n\n\n\n<p>&nbsp; return filenames<\/p>\n\n\n\n<p><em>def<\/em> getBestMatchIndex(<em>input_avg<\/em>, <em>avgs<\/em>):<\/p>\n\n\n\n<p>&nbsp; &#8220;&#8221;&#8221;<\/p>\n\n\n\n<p>&nbsp; return index of best Image match based on RGB value distance<\/p>\n\n\n\n<p>&nbsp; &#8220;&#8221;&#8221;<\/p>\n\n\n\n<p>&nbsp; # input image average<\/p>\n\n\n\n<p>&nbsp; avg = <em>input_avg<\/em><\/p>\n\n\n\n<p>&nbsp; # get the closest RGB value to input, based on x\/y\/z distance<\/p>\n\n\n\n<p>&nbsp; index = 0<\/p>\n\n\n\n<p>&nbsp; min_index = 0<\/p>\n\n\n\n<p>&nbsp; min_dist = float(&#8220;inf&#8221;)<\/p>\n\n\n\n<p>&nbsp; for val in <em>avgs<\/em>:<\/p>\n\n\n\n<p>&nbsp; &nbsp; dist = ((val[0] &#8211; avg[0])*(val[0] &#8211; avg[0]) +<\/p>\n\n\n\n<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (val[1] &#8211; avg[1])*(val[1] &#8211; avg[1]) +<\/p>\n\n\n\n<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (val[2] &#8211; avg[2])*(val[2] &#8211; avg[2]))<\/p>\n\n\n\n<p>&nbsp; &nbsp; if dist &lt; min_dist:<\/p>\n\n\n\n<p>&nbsp; &nbsp; &nbsp; min_dist = dist<\/p>\n\n\n\n<p>&nbsp; &nbsp; &nbsp; min_index = index<\/p>\n\n\n\n<p>&nbsp; &nbsp; index += 1<\/p>\n\n\n\n<p>&nbsp; return min_index<\/p>\n\n\n\n<p><em>def<\/em> createImageGrid(<em>images<\/em>, <em>dims<\/em>):<\/p>\n\n\n\n<p>&nbsp; &#8220;&#8221;&#8221;<\/p>\n\n\n\n<p>&nbsp; Given a list of images and a grid size (m, n), create<\/p>\n\n\n\n<p>&nbsp; a grid of images.<\/p>\n\n\n\n<p>&nbsp; &#8220;&#8221;&#8221;<\/p>\n\n\n\n<p>&nbsp; m, n = <em>dims<\/em><\/p>\n\n\n\n<p>&nbsp; # sanity check<\/p>\n\n\n\n<p>&nbsp; assert m*n == len(<em>images<\/em>)<\/p>\n\n\n\n<p>&nbsp; # get max height and width of images<\/p>\n\n\n\n<p>&nbsp; # ie, not assuming they are all equal<\/p>\n\n\n\n<p>&nbsp; width = max([img.size[0] for img in <em>images<\/em>])<\/p>\n\n\n\n<p>&nbsp; height = max([img.size[1] for img in <em>images<\/em>])<\/p>\n\n\n\n<p>&nbsp; # create output image<\/p>\n\n\n\n<p>&nbsp; grid_img = Image.new(&#8216;RGB&#8217;, (n*width, m*height))<\/p>\n\n\n\n<p>&nbsp; # paste images<\/p>\n\n\n\n<p>&nbsp; for index in range(len(<em>images<\/em>)):<\/p>\n\n\n\n<p>&nbsp; &nbsp; row = int(index\/n)<\/p>\n\n\n\n<p>&nbsp; &nbsp; col = index &#8211; n*row<\/p>\n\n\n\n<p>&nbsp; &nbsp; grid_img.paste(<em>images<\/em>[index], (col*width, row*height))<\/p>\n\n\n\n<p>&nbsp; return grid_img<\/p>\n\n\n\n<p><em>def<\/em> createPhotomosaic(<em>target_image<\/em>, <em>input_images<\/em>, <em>grid_size<\/em>,<\/p>\n\n\n\n<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <em>reuse_images<\/em>=True):<\/p>\n\n\n\n<p>&nbsp; &#8220;&#8221;&#8221;<\/p>\n\n\n\n<p>&nbsp; Creates photomosaic given target and input images.<\/p>\n\n\n\n<p>&nbsp; &#8220;&#8221;&#8221;<\/p>\n\n\n\n<p>&nbsp; print(&#8216;splitting input image&#8230;&#8217;)<\/p>\n\n\n\n<p>&nbsp; # split target image<\/p>\n\n\n\n<p>&nbsp; target_images = splitImage(<em>target_image<\/em>, <em>grid_size<\/em>)<\/p>\n\n\n\n<p>&nbsp; print(&#8216;finding image matches&#8230;&#8217;)<\/p>\n\n\n\n<p>&nbsp; # for each target image, pick one from input<\/p>\n\n\n\n<p>&nbsp; output_images = []<\/p>\n\n\n\n<p>&nbsp; # for user feedback<\/p>\n\n\n\n<p>&nbsp; count = 0<\/p>\n\n\n\n<p>&nbsp; batch_size = int(len(target_images)\/10)<\/p>\n\n\n\n<p>&nbsp; # calculate input image averages<\/p>\n\n\n\n<p>&nbsp; avgs = []<\/p>\n\n\n\n<p>&nbsp; for img in <em>input_images<\/em>:<\/p>\n\n\n\n<p>&nbsp; &nbsp; avgs.append(getAverageRGB(img))<\/p>\n\n\n\n<p>&nbsp; for img in target_images:<\/p>\n\n\n\n<p>&nbsp; &nbsp; # target sub-image average<\/p>\n\n\n\n<p>&nbsp; &nbsp; avg = getAverageRGB(img)<\/p>\n\n\n\n<p>&nbsp; &nbsp; # find match index<\/p>\n\n\n\n<p>&nbsp; &nbsp; match_index = getBestMatchIndex(avg, avgs)<\/p>\n\n\n\n<p>&nbsp; &nbsp; output_images.append(<em>input_images<\/em>[match_index])<\/p>\n\n\n\n<p>&nbsp; &nbsp; # user feedback<\/p>\n\n\n\n<p>&nbsp; &nbsp; if count &gt; 0 and batch_size &gt; 10 and count % batch_size is 0:<\/p>\n\n\n\n<p>&nbsp; &nbsp; &nbsp; print(&#8216;processed %d of %d&#8230;&#8217; %(count, len(target_images)))<\/p>\n\n\n\n<p>&nbsp; &nbsp; count += 1<\/p>\n\n\n\n<p>&nbsp; &nbsp; # remove selected image from input if flag set<\/p>\n\n\n\n<p>&nbsp; &nbsp; if not <em>reuse_images<\/em>:<\/p>\n\n\n\n<p>&nbsp; &nbsp; &nbsp; <em>input_images<\/em>.remove(match)<\/p>\n\n\n\n<p>&nbsp; print(&#8216;creating mosaic&#8230;&#8217;)<\/p>\n\n\n\n<p>&nbsp; # draw mosaic to image<\/p>\n\n\n\n<p>&nbsp; mosaic_image = createImageGrid(output_images, <em>grid_size<\/em>)<\/p>\n\n\n\n<p>&nbsp; # return mosaic<\/p>\n\n\n\n<p>&nbsp; return mosaic_image<\/p>\n\n\n\n<p># Gather our code in a main() function<\/p>\n\n\n\n<p><em>def<\/em> main():<\/p>\n\n\n\n<p>&nbsp; # Command line args are in sys.argv[1], sys.argv[2] ..<\/p>\n\n\n\n<p>&nbsp; # sys.argv[0] is the script name itself and can be ignored<\/p>\n\n\n\n<p>&nbsp; # parse arguments<\/p>\n\n\n\n<p>&nbsp; parser = argparse.ArgumentParser(<em>description<\/em>=&#8217;Creates a photomosaic from input images&#8217;)<\/p>\n\n\n\n<p>&nbsp; # add arguments<\/p>\n\n\n\n<p>&nbsp; parser.add_argument(&#8216;&#8211;target-image&#8217;, <em>dest<\/em>=&#8217;target_image&#8217;, <em>required<\/em>=True)<\/p>\n\n\n\n<p>&nbsp; parser.add_argument(&#8216;&#8211;input-folder&#8217;, <em>dest<\/em>=&#8217;input_folder&#8217;, <em>required<\/em>=True)<\/p>\n\n\n\n<p>&nbsp; parser.add_argument(&#8216;&#8211;grid-size&#8217;, <em>nargs<\/em>=2, <em>dest<\/em>=&#8217;grid_size&#8217;, <em>required<\/em>=True)<\/p>\n\n\n\n<p>&nbsp; parser.add_argument(&#8216;&#8211;output-file&#8217;, <em>dest<\/em>=&#8217;outfile&#8217;, <em>required<\/em>=False)<\/p>\n\n\n\n<p>&nbsp; args = parser.parse_args()<\/p>\n\n\n\n<p>&nbsp; ###### INPUTS ######<\/p>\n\n\n\n<p>&nbsp; # target image<\/p>\n\n\n\n<p>&nbsp; target_image = Image.open(args.target_image)<\/p>\n\n\n\n<p>&nbsp; # input images<\/p>\n\n\n\n<p>&nbsp; print(&#8216;reading input folder&#8230;&#8217;)<\/p>\n\n\n\n<p>&nbsp; input_images = getImages(args.input_folder)<\/p>\n\n\n\n<p>&nbsp; # check if any valid input images found &nbsp;<\/p>\n\n\n\n<p>&nbsp; if input_images == []:<\/p>\n\n\n\n<p>&nbsp; &nbsp; &nbsp; print(&#8216;No input images found in %s. Exiting.&#8217; % (args.input_folder, ))<\/p>\n\n\n\n<p>&nbsp; &nbsp; &nbsp; exit()<\/p>\n\n\n\n<p>&nbsp; # shuffle list &#8211; to get a more varied output?<\/p>\n\n\n\n<p>&nbsp; random.shuffle(input_images)<\/p>\n\n\n\n<p>&nbsp; # size of grid<\/p>\n\n\n\n<p>&nbsp; grid_size = (int(args.grid_size[0]), int(args.grid_size[1]))<\/p>\n\n\n\n<p>&nbsp; # output<\/p>\n\n\n\n<p>&nbsp; output_filename = &#8216;mosaic.png&#8217;<\/p>\n\n\n\n<p>&nbsp; if args.outfile:<\/p>\n\n\n\n<p>&nbsp; &nbsp; output_filename = args.outfile<\/p>\n\n\n\n<p>&nbsp; # re-use any image in input<\/p>\n\n\n\n<p>&nbsp; reuse_images = True<\/p>\n\n\n\n<p>&nbsp; # resize the input to fit original image size?<\/p>\n\n\n\n<p>&nbsp; resize_input = True<\/p>\n\n\n\n<p>&nbsp; ##### END INPUTS #####<\/p>\n\n\n\n<p>&nbsp; print(&#8216;starting photomosaic creation&#8230;&#8217;)<\/p>\n\n\n\n<p>&nbsp; # if images can&#8217;t be reused, ensure m*n &lt;= num_of_images<\/p>\n\n\n\n<p>&nbsp; if not reuse_images:<\/p>\n\n\n\n<p>&nbsp; &nbsp; if grid_size[0]*grid_size[1] &gt; len(input_images):<\/p>\n\n\n\n<p>&nbsp; &nbsp; &nbsp; print(&#8216;grid size less than number of images&#8217;)<\/p>\n\n\n\n<p>&nbsp; &nbsp; &nbsp; exit()<\/p>\n\n\n\n<p>&nbsp; # resizing input<\/p>\n\n\n\n<p>&nbsp; if resize_input:<\/p>\n\n\n\n<p>&nbsp; &nbsp; print(&#8216;resizing images&#8230;&#8217;)<\/p>\n\n\n\n<p>&nbsp; &nbsp; # for given grid size, compute max dims w,h of tiles<\/p>\n\n\n\n<p>&nbsp; &nbsp; dims = (int(target_image.size[0]\/grid_size[1]),<\/p>\n\n\n\n<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; int(target_image.size[1]\/grid_size[0]))<\/p>\n\n\n\n<p>&nbsp; &nbsp; print(&#8220;max tile dims: %s&#8221; % (dims,))<\/p>\n\n\n\n<p>&nbsp; &nbsp; # resize<\/p>\n\n\n\n<p>&nbsp; &nbsp; for img in input_images:<\/p>\n\n\n\n<p>&nbsp; &nbsp; &nbsp; img.thumbnail(dims)<\/p>\n\n\n\n<p>&nbsp; # create photomosaic<\/p>\n\n\n\n<p>&nbsp; mosaic_image = createPhotomosaic(target_image, input_images, grid_size,<\/p>\n\n\n\n<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;reuse_images)<\/p>\n\n\n\n<p>&nbsp; # write out mosaic<\/p>\n\n\n\n<p>&nbsp; mosaic_image.save(output_filename, &#8216;PNG&#8217;)<\/p>\n\n\n\n<p>&nbsp; print(&#8220;saved output to %s&#8221; % (output_filename,))<\/p>\n\n\n\n<p>&nbsp; print(&#8216;done.&#8217;)<\/p>\n\n\n\n<p># Standard boilerplate to call the main() function to begin<\/p>\n\n\n\n<p># the program.<\/p>\n\n\n\n<p>if __name__ == &#8216;__main__&#8217;:<\/p>\n\n\n\n<p>&nbsp; main()<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I made a Photomosaic program with a book tutorial heres the code with proper credit &#8220;&#8221;&#8221; photomosaic.py Creates a photomosaic [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"categories":[1],"tags":[],"class_list":["post-57","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/theroyalscode.com\/students\/l_rankins\/wp-json\/wp\/v2\/posts\/57","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/theroyalscode.com\/students\/l_rankins\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/theroyalscode.com\/students\/l_rankins\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/theroyalscode.com\/students\/l_rankins\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/theroyalscode.com\/students\/l_rankins\/wp-json\/wp\/v2\/comments?post=57"}],"version-history":[{"count":1,"href":"https:\/\/theroyalscode.com\/students\/l_rankins\/wp-json\/wp\/v2\/posts\/57\/revisions"}],"predecessor-version":[{"id":58,"href":"https:\/\/theroyalscode.com\/students\/l_rankins\/wp-json\/wp\/v2\/posts\/57\/revisions\/58"}],"wp:attachment":[{"href":"https:\/\/theroyalscode.com\/students\/l_rankins\/wp-json\/wp\/v2\/media?parent=57"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/theroyalscode.com\/students\/l_rankins\/wp-json\/wp\/v2\/categories?post=57"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/theroyalscode.com\/students\/l_rankins\/wp-json\/wp\/v2\/tags?post=57"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}