How to straighten the images given any orientation of the images - image

I have tried an algorithm to rotate the images, but it doesn't help in straightening my images given the image can have any orientation from 0 to 180/360 degrees.
Example images:
Image 1:
Image 2:
Image 3:
My code:
# import the necessary packages
import matplotlib.pyplot as plt
import numpy as np
import argparse
import cv2
import copy
def plt_imshow(title, image):
# display the image
plt.imshow(image)
plt.title(title)
plt.grid(False)
plt.show()
args = {
"image": "C:/Users/tskta/Desktop/Images rotation/all
rotations/75.png"}
# load the image from disk
image = cv2.imread(args["image"])
#convert the image to greyscale and flip the foreground and
background
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gray = cv2.bitwise_not(gray)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY |
cv2.THRESH_OTSU)[1]
#grab the x,y coordinates of all pixel values that are greater than
zero
#and form a rotating bounding box
coords = np.column_stack(np.where(thresh > 0))
angle = cv2.minAreaRect(coords)[-1]
print(angle)
if -45 > angle >-89:
angle = -(90 + angle)
elif angle == -90.0:
angle = -angle
else:
angle = -angle
print(angle)
# rotate the image to deskew it
(h, w) = image.shape[:2]
center = (w // 2, h // 2)
M = cv2.getRotationMatrix2D(center, angle, 1.0)
rotated = cv2.warpAffine(image, M, (w, h),
flags=cv2.INTER_CUBIC, borderMode=cv2.BORDER_REPLICATE)
# draw the correction angle on the image so we can validate it
cv2.putText(rotated, "Angle: {:.2f} degrees".format(angle),
(10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
# show the output image
print("[INFO] angle: {:.3f}".format(angle))
plt_imshow("Input", image)
plt_imshow("Rotated", rotated)
cv2.imwrite("Downloads/rotated.png", rotated)

Your Python/OpenCV code looks fine except that the angle test does not take into account that the object is going to need to be rotated to portrait mode.
The following does that by computing the direction of the edge with the largest length and then aligning (unrotating) to the vertical (Y) axis.
The code below takes a white rectangle and rotates it between -90 and 90 in 10 deg increments. The assumption is that the scan of the documents will be such that the top of the bill is in the top half of the image, thus satisfying the assumption.
Input:
import cv2
import numpy as np
import math
# unrotation to portrait mode
# read input
img = cv2.imread('vertical_rect.png')
hh, ww = img.shape[:2]
# compute center
cx = ww // 2
cy = hh // 2
# rotated input in range -90 to 90 inclusive
# assume scanned so always in that range
# do unrotation by using the longest edge of rectangle to find the direction
# and unrotate so that it aligns with the vertical (Y) axis upwards
for rotation in range(-90,100,10):
# rotate image
matrix = cv2.getRotationMatrix2D((cx,cy), rotation, 1.0)
img_rotated = cv2.warpAffine(img, matrix, (ww, hh), flags=cv2.INTER_CUBIC, borderMode=cv2.BORDER_REPLICATE)
# convert to gray
gray = cv2.cvtColor(img_rotated, cv2.COLOR_BGR2GRAY)
# threshold (must be convex, so use morphology to close up if needed)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY)[1]
# find all non-zero pixel coordinates
# swap x and y for conversion from numpy y,x to opencv x,y ordering via transpose
coords = np.column_stack(np.where(thresh.transpose() > 0))
# get minAreaRect and its vertices
rotrect = cv2.minAreaRect(coords)
pts = cv2.boxPoints(rotrect)
#print(pts)
list = []
# compute edge lengths and directions (in range -90 to 90) and put into list
polygon = img_rotated.copy()
for i in range(0,4):
i1 = i
i2 = i+1 if i!=3 else 0
pt1 = pts[i1]
pt2 = pts[i2]
pt1x = pt1[0]
pt2x = pt2[0]
pt1y = pt1[1]
pt2y = pt2[1]
length = math.sqrt( (pt2x-pt1x)*(pt2x-pt1x) + (pt2y-pt1y)*(pt2y-pt1y) )
direction = (180/math.pi)*math.atan2( (pt2y-pt1y), (pt2x-pt1x) )
list.append([length, direction, pt1])
# optional: draw lines around box points on input (rotated)
# points start at left most point (and top most to break ties)
# and go clockwise around rectangle
# first point is blue and second point is green to show direction
x1 = int(pt1x)
y1 = int(pt1y)
x2 = int(pt2x)
y2 = int(pt2y)
if i == 0:
cv2.circle(polygon,(x1,y1),7,(255,0,0),-1)
cv2.circle(polygon,(x2,y2),5,(0,255,0),-1)
cv2.line(polygon, (x1,y1), (x2,y2), (0,0,255), 2)
else:
cv2.line(polygon, (x1,y1), (x2,y2), (0,0,255), 2)
# sort list on length with largest first
def takeFirst(elem):
return elem[0]
list.sort(key=takeFirst, reverse=True)
# get direction of largest length and correct to -90 to 90 range
item = list[0]
dir = item[1]
if dir < -90:
dir = dir + 180
if dir > 90:
dir = dir - 180
# correct to portrait mode
# if dir is negative or zero, then add 90; otherwise subtract 90
# dir = 0 occurs for both 0 and 90, so both cannot be determined -- pick one
if dir <= 0:
unrotate = dir + 90
else:
unrotate = dir - 90
print("initial rotation=", rotation, "edge direction=", dir, "unrotation angle=", unrotate)
# unrotate image
M = cv2.getRotationMatrix2D((cx, cy), unrotate, 1.0)
img_unrotated = cv2.warpAffine(img_rotated, M, (ww, hh), flags=cv2.INTER_CUBIC, borderMode=cv2.BORDER_REPLICATE)
#cv2.imshow('img_rotated', img_rotated)
cv2.imshow('polygon', polygon)
cv2.imshow('img_unrotated', img_unrotated)
cv2.waitKey()
# optional save output
#cv2.imwrite("vertical_rect_{0}.png".format(rotation), img_unrotated)
Results:
initial rotation= -90 edge direction= 0.0 unrotation angle= 90.0
initial rotation= -80 edge direction= -10.024489033132815 unrotation angle= 79.97551096686719
initial rotation= -70 edge direction= -19.922231300954746 unrotation angle= 70.07776869904525
initial rotation= -60 edge direction= -30.000354626107335 unrotation angle= 59.99964537389266
initial rotation= -50 edge direction= -39.98688344835102 unrotation angle= 50.01311655164898
initial rotation= -40 edge direction= -50.00064126059898 unrotation angle= 39.99935873940102
initial rotation= -30 edge direction= -60.00891266459192 unrotation angle= 29.991087335408082
initial rotation= -20 edge direction= -70.07776869904525 unrotation angle= 19.92223130095475
initial rotation= -10 edge direction= -79.97551600323786 unrotation angle= 10.024483996762143
initial rotation= 0 edge direction= 90.0 unrotation angle= 0.0
initial rotation= 10 edge direction= 79.97550927006476 unrotation angle= -10.024490729935238
initial rotation= 20 edge direction= 70.07776869904525 unrotation angle= -19.92223130095475
initial rotation= 30 edge direction= 59.99507091100694 unrotation angle= -30.00492908899306
initial rotation= 40 edge direction= 50.013119348261796 unrotation angle= -39.986880651738204
initial rotation= 50 edge direction= 39.99936207636015 unrotation angle= -50.00063792363985
initial rotation= 60 edge direction= 29.991085160541278 unrotation angle= -60.008914839458726
initial rotation= 70 edge direction= 19.922231300954746 unrotation angle= -70.07776869904525
initial rotation= 80 edge direction= 10.02448431018454 unrotation angle= -79.97551568981547
initial rotation= 90 edge direction= 0.0 unrotation angle= 90.0

Related

matlab plot data over an image

I would like to plot a scatter plot over a background image. But the origin of the image is at the top left corner. I need the bottom left of the image to be the origin so the bottom left = (0, 0.75) and top right (14, 1.25)
So I need to scale the image to my data from pH 0 - 14 (This is the x axis) and Eh 0.75 - 1.25 (This is the y axis)
Eh = [327.06 561.34 506.82 602.58 745.02 745.04 ...
693.96 682.9 648.46 468 412.18 522.94 459.74]./1e3; % V
pH = [6.4 4.51 5.08 4.98 3.63 4.31 6.24 6.22 4.94 6.44 7.05 5.09 4.63]; %pH
I=imread('Fe_Pourbaix.png');
xImg = linspace(0, 14, size(I, 2));
yImg = linspace(-0.75, 1.25, size(I, 1));
image(xImg, yImg, I, 'CDataMapping', 'scale');
hold on;
plot(pH, Eh,'*','LineWidth',2);
grid on;
Suppose I Need to flip the data? The below image is what I need is the x and y I need to produce to overlay my data

Fast Radial Symmetry Transform (FRST) implementation (python) results in unusual cross-hair looking artifacts

I am trying to implement FRST on python to detect centroids of elliptical objects (e.g. cells in microscopy images), but my implementation does not find seed points (more or less center points) of elliptical objects. This effort comes from duplicating FRST from Segmentation of Overlapping Elliptical Objects in Silhouette Images (https://ieeexplore.ieee.org/document/7300433). I don't know why I have these artifacts. An interesting thing is that I see these patterns (crosses) all in the same direction per object. Any point in the right direction to generate the same result as in the paper (just to find the seed points) will be most welcome.
Original Paper: A Fast Radial Symmetry Transform for Detecting Points of Interest by Loy and Zelinsky (ECCV 2002)
I have also tried the pre-existing python package for FRST: https://pypi.org/project/frst/. This somehow results in the same artifacts. Weird.
First image: Original Image
Second image: Sobel-operated Image
Third image: Magnitude Projection Image
Fourth image: Magnitude Projection Image with positively affected pixels only
Fifth image: FRST'd image: end-product with original image overlaid (shadowed)
Sixth image: FRST'd image by the pre-existing python package with original image overlaid (shadowed).
from scipy.ndimage import gaussian_filter
import numpy as np
from scipy.signal import convolve
# Get orientation projection image
def get_proj_img(image, radius):
workingDims = tuple((e + 2*radius) for e in image.shape)
h,w = image.shape
ori_img = np.zeros(workingDims) # Orientation Projection Image
mag_img = np.zeros(workingDims) # Magnitutde Projection Image
# Kenels for the sobel operator
a1 = np.matrix([1, 2, 1])
a2 = np.matrix([-1, 0, 1])
Kx = a1.T * a2
Ky = a2.T * a1
# Apply the Sobel operator
sobel_x = convolve(image, Kx)
sobel_y = convolve(image, Ky)
sobel_norms = np.hypot(sobel_x, sobel_y)
# Distances to afpx, afpy (affected pixels)
dist_afpx = np.multiply(np.divide(sobel_x, sobel_norms, out = np.zeros(sobel_x.shape), where = sobel_norms!=0), radius)
dist_afpx = np.round(dist_afpx).astype(int)
dist_afpy = np.multiply(np.divide(sobel_y, sobel_norms, out = np.zeros(sobel_y.shape), where = sobel_norms!=0), radius)
dist_afpy = np.round(dist_afpy).astype(int)
for cords, sobel_norm in np.ndenumerate(sobel_norms):
i, j = cords
pos_aff_pix = (i+dist_afpx[i,j], j+dist_afpy[i,j])
neg_aff_pix = (i-dist_afpx[i,j], j-dist_afpy[i,j])
ori_img[pos_aff_pix] += 1
ori_img[neg_aff_pix] -= 1
mag_img[pos_aff_pix] += sobel_norm
mag_img[neg_aff_pix] -= sobel_norm
ori_img = ori_img[:h, :w]
mag_img = mag_img[:h, :w]
print ("Did it go back to the original image size? ")
print (ori_img.shape == image.shape)
# try normalizing ori and mag img
return ori_img, mag_img
def get_sn(ori_img, mag_img, radius, kn, alpha):
ori_img_limited = np.minimum(ori_img, kn)
fn = np.multiply(np.divide(mag_img,kn), np.power((np.absolute(ori_img_limited)/kn), alpha))
# convolute fn with gaussian filter.
sn = gaussian_filter(fn, 0.25*radius)
return sn
def do_frst(image, radius, kn, alpha, ksize = 3):
ori_img, mag_img = get_proj_img(image, radius)
sn = get_sn(ori_img, mag_img, radius, kn, alpha)
return sn
Parameters:
radius = 50
kn = 10
alpha = 2
beta = 0
stdfactor = 0.25

How to find the centroid of pixels with same color in a 360° video?

Let I be a w x h frame from a 360° video stream.
Let R be a red rectangle on that frame. R is smaller than the width of the image.
To compute the centroid of this rectangle we need to distinguish two cases:
case 1 where R is on the edges
case 2 where R is fully inside the frame
As you can see there will be a problem to compute the centroid with classical methods in case 1. Please note that I only care about horizontal overlapping.
For the moment I am doing like this. First we detect the first point we find and use it as a reference, then we normalize dx which is the difference between a point and the reference and then we accumulate:
width = frame.width
rectangle_pixel = (255,0,0)
first_found_coord = (-1,-1)
centroid = (0,0)
centroid_count = 0
for pixel, coordinates in image:
if(pixel != rectangle_pixel):
continue
if(first_found_coord == (-1,-1)):
first_found_coord = coordinates
centroid = coordinates
continue
dx = coordinates.x - first_found_coord.x
if(dx > width/2):
dx -= width
else if(dx < - width/2):
dx -= width
centroid += (dx, coordinates.y)
centroid_count++
final_centroid = centroid / centroid_count
But it doesn't work as expected. Where is the problem, is there a faster solution ?
Here is a solution based on transition points, i.e when you move from red to non red, or in the other way. To capture the horizontal center, I needed the following information :
gridSize.x : width of the space where rectangles can live.
w : width of your rectangle.
PseudoCode:
redPixel = (255,0,0);
transitionPoints = [];
betweenTransitionsColor = -1;
// take i and i+1 pixel+position, increment i by one at each step.
for (pixel1, P1), (pixel1, P2) in gridX : // horizontal points for a fixed `y`
if pixel1 != pixel2: // one is red, the other white
nonRedPosition = (pixel1 != redPixel ? P1 : P2)
transitionPoints.append(nonRedPosition)
continue
if(transitionPoints.length == 1 && betweenTransitionsColor == -1):
betweenTransitionsColor = pixel2
if transitionPoints.length == 2:
break
//Case where your rectangle is on the edge (left or right)
if(transitionPoints.length == 1):
if(abs(transitionPoints[0].x - w) < 2):
xCenter = w/2
else:
xCenter = gridSize.x - w/2
else:
[tP1, tP2] = transitionPoints
// case 1 : The rectangle is splitted
if betweenTransitionsColor != redPixel:
xCenter = (tP2.x - gridSize.x + tP1.x)/2
else:
xCenter = (tP1.x + tP1.x)/2
Note :
you must start at a y position where you could get red pixels. This shouldn't be very hard to achieve. If your rectangle's height is bigger than gridSize.y/2, you can begin at gridSize.y/2. Otherwise, you can search for a first red pixel, and set y to the corresponding position.
Since I'm computing the bounding boxes in the same scope, I do it in two steps.
I first accumulate the coordinates of the pixels of interest. Then when I'm checking for overlapping bounding boxes, I subtract the with for each overlapping colors on the right half of the image. So I end up with a completed but slided rectangle.
At the end I divide by the number of point found per color. If the result is negative I shift it by the size of width of the image.
Alternatively:
def get_centroid(image, interest_color):
acc_x = 0
acc_y = 0
count = 0
first_pixel = (0,0)
for (x,y, color) in image:
if(color not in interest_color):
continue
if(count == 0):
first_pixel = (x,y)
dx = x - first_pixel.x
if(dx > L/2)
dx -= L
else if (dx < -L/2)
dx += L
acc_x += x
acc_y += y
count++
non_scaled_result = acc_x / count, acc_y / count
result = non_scaled_result + first_pixel
return result

3D reconstruction from a 2D image in MATLAB

I have some difficulties to reconstruct a 3D scene from a 2D image under Matlab.
I would like to create a top view of scene removing the perspective, in other words, realize an inverse perspective mapping.
Let's assume we know the camera position, orientation and its parameters. Moreover we consider all the captured points lie on the same plane XY.
Then, it is easy to prove that a pixel at a (u,v) location in the image will move to the coordinate (X,Y,0) in the 3D space with:
X=-((u*P(3,4)-P(1,4))*(v*P(3,1)-P(2,1)) + (v*P(3,4)-P(2,4))*(P(1,1)-u*P(3,1)))/((u*P(3,2)-P(1,2))*(v*P(3,1)-P(2,1)) + (v*P(3,2)-P(2,2))*(P(1,1)-u*P(3,1)));
Y=(X*(u*P(3,2)-P(1,2)) + (u*P(3,4)-P(1,4)))/(P(1,1)-u*P(3,1));
P is the projection matrix such that: P=[KR KT] with K,R and T respectively the intrinsic, rotation and translation matrices.
Once all the 3D locations of each pixel are computed, I would like to display the XY plane with the color information of the original pixel as if it was a 2D image.
However, a pixel (u,v) can mapped in 3D space to a non integer location meaning that I get a non-regular scatter plot were each (X,Y) point contain a color information.
I tried to divide the XY plane into small windows and then compute the average color of all points into each squares but it is very slow.
Please find my code below.
Some help would be appreciated.
Thank you in advance,
Pm
% This program aims to convert a 2D image into a 3D scenario. Let's assume that
% all the points in the image lie on the same plan in the 3D space.
% Program:
% 1-Generate the 3D scenario with 4 squares from diferrent colors
% 2-Take a picture of these squares by projecting the scene into an image 2D space
% 3-Reconstruct the 3D scene from the 2D picture
% Author: Pierre-Marie Damon
clear all; close all; clc;
%% 4 SQUARES DEFINITION
c=10;
sq1_3D = [ 0 0 0;
0 c 0;
c c 0;
c 0 0];
sq2_3D = [ 0 0 0;
c 0 0;
c -c 0;
0 -c 0];
sq3_3D = [ 0 0 0;
0 -c 0;
-c -c 0;
-c 0 0];
sq4_3D = [ 0 0 0;
-c 0 0;
-c c 0;
0 c 0];
SQ_3D = [sq1_3D;
sq2_3D;
sq3_3D;
sq4_3D];
%% CAMERA DEFINITION
% Image resolution:
image_size = [640,480];
% Intrinsic matrix:
fx=150; fy=150; % fx, fy: focal lengths in pixel
x0=image_size(1)/2; y0=image_size(2)/2; % x0, y0: optical center projection coordinates in the 2D cxamera space
K = [fx 0 x0 ;
0 fy y0 ;
0 0 1 ];
% 3D camera orientation:
Rot_cam = [ 0 0 1;
-1 0 0;
0 -1 0]';
% 3D camera rotations:
yaw = -20*pi/180;
roll = -0*pi/180;
pitch = -20*pi/180;
% 3D camera position:
O_Rcam = [-20;0;10];
h_cam = O_Rcam(3); % camera height
% Projection & transformation matrices
R = rotationVectorToMatrix([pitch,yaw,roll])*Rot_cam; % Rotation matrix
T = -R*O_Rcam; % Translation matrix
P = [K*R K*T; zeros(1,3) 1]; %Projection Matrix
%% PROJECTION FROM 3D TO THE 2D IMAGE
SQ_2D = (P*[SQ_3D ones(size(SQ_3D,1),1)]')'; % homogeneous coordinates
SQ_2D = SQ_2D(:,1:2)./repmat(SQ_2D(:,3),1,2); % Normalization
% Square splits:
sq1_2D = SQ_2D(1:4,:);
sq2_2D = SQ_2D(5:8,:);
sq3_2D = SQ_2D(9:12,:);
sq4_2D = SQ_2D(13:16,:);
%% PLOT THE 3D SCENARIO
figure('units','normalized','outerposition',[0 0 1 1]);
f1=subplot(1,2,1);hold on; grid on; view(50, 30); axis equal;
xlabel('X');ylabel('Y');zlabel('Z'); title('3D Scene');
% Plot the camera
cam = plotCamera('Location',O_Rcam,'Orientation',R,'Size',1,'AxesVisible',0);
% Plot the squares
patch([sq1_3D(:,1)],[sq1_3D(:,2)],'r','EdgeColor','k');
patch([sq2_3D(:,1)],[sq2_3D(:,2)],'g','EdgeColor','k');
patch([sq3_3D(:,1)],[sq3_3D(:,2)],'b','EdgeColor','k');
patch([sq4_3D(:,1)],[sq4_3D(:,2)],'m','EdgeColor','k');
%% PLOT THE 2D IMAGE
f2=subplot(1,2,2); hold on; grid on; axis equal; set(gca,'YDir','Reverse'); title('2D Image'); axis off;
xlim([0 image_size(1)]); ylim([0 image_size(2)]);
% plot the projected squares
patch ([sq1_2D(:,1)],[sq1_2D(:,2)],'r','EdgeColor','none');
patch ([sq2_2D(:,1)],[sq2_2D(:,2)],'g','EdgeColor','none');
patch ([sq3_2D(:,1)],[sq3_2D(:,2)],'b','EdgeColor','none');
patch ([sq4_2D(:,1)],[sq4_2D(:,2)],'m','EdgeColor','none');
% Plot the image borders
plot([0 image_size(1)],[0 0],'k','linewidth',3);
plot([image_size(1) image_size(1)],[0 image_size(2)],'k','linewidth',3);
plot([0 image_size(1)],[image_size(2) image_size(2)],'k','linewidth',3);
plot([0 0],[0 image_size(2)],'k','linewidth',3);
%% GENERATE A JPG IMAGE
figure; hold on; grid on; set(gca,'YDir','Reverse'); axis off;
hFig = gcf; hAx = gca; % get the figure and axes handles
set(hFig,'units','normalized','outerposition',[0 0 1 1]); % set the figure to full screen
set(hAx,'Unit','normalized','Position',[0 0 1 1]); % set the axes to full screen
set(hFig,'menubar','none'); % hide the toolbar
set(hFig,'NumberTitle','off'); % to hide the title
xlim([0 image_size(1)]); ylim([0 image_size(2)]);
% Plot the squares
patch ([sq1_2D(:,1)],[sq1_2D(:,2)],'r','EdgeColor','none');
patch ([sq2_2D(:,1)],[sq2_2D(:,2)],'g','EdgeColor','none');
patch ([sq3_2D(:,1)],[sq3_2D(:,2)],'b','EdgeColor','none');
patch ([sq4_2D(:,1)],[sq4_2D(:,2)],'m','EdgeColor','none');
% Create the image
set(gcf,'PaperUnits','inches','PaperPosition',[0 0 image_size(1)/100 image_size(2)/100])
print -djpeg Image.jpg -r100
save('ImageParam.mat', 'K','R','T','P','O_Rcam' )
%% 3D RECONSTRUCTION FROM 2D IMAGE
clear all;
close all;
clc;
load('ImageParam');
I=imread('Image.jpg');
I1 = rgb2gray(I);
figure;imshow(I1);impixelinfo;
I2 = zeros(size(I1));
k=1; i=1; j=1;
tic
for y=size(I2,1):-1:1
for x=1:size(I2,2)
% The formula below comes from the projection equations of
% the camera and the additional constraint that all the points lie on the XY
% plane
X(k)=-((x*P(3,4)-P(1,4))*(y*P(3,1)-P(2,1)) + (y*P(3,4)-P(2,4))*(P(1,1)-x*P(3,1)))/((x*P(3,2)-P(1,2))*(y*P(3,1)-P(2,1)) + (y*P(3,2)-P(2,2))*(P(1,1)-x*P(3,1)));
Y(k)=(X(k)*(x*P(3,2)-P(1,2)) + (x*P(3,4)-P(1,4)))/(P(1,1)-x*P(3,1));
Z(k)=0;
C(k)=I1(y,x); % Color (gray intensity) information
k=k+1;
end
end
toc
figure;hold on;axis equal;
plot(X,Y,'.');
grid on;

Animating With Gloss in Haskell

Here's my code for a little pattern that looks something like this. (Not the most efficient code I know). Now, I want to make stars rotate using animate. but I'm not sure how to use display and animate together in one program. Any help would be appreciated. Thanks.
import Graphics.Gloss
main = display (InWindow "Gloss" (700,700) (0,0))
black (picture 100)
picture :: Float -> Picture
picture 0 = text "Value cannot be 0"
picture number = scale 6.5 6.5 (color rose $ drawpicture number)
orangered, orangered2, orangered3 :: Color
orangered = makeColor 1.0 0.251 0.0 0.7
orangered2 = makeColor 1.0 0.251 0.0 0.5
orangered3 = makeColor 1.0 0.251 0.0 0.3
intervalsmall = [0,11.25,22.5,33.75,45,56.25,67.5,78.75]
intervalbig = [0,22.5,45,67.5,90,112.5,135,157.5,180,202.5,225,247.5,270,292.5,315,337.5]
xlist = [2,4..50]
ylist = [0,2..48]
squares = pictures[rotate x (line [(-50,0),(0,50),(50,0),(0,-50),(-50,0)]) | x <- intervalsmall]
stars = pictures[rotate x ((pictures [line [(-8.5,0),(0,50),(8.5,0)],line[(0,50),(0,0)]])) | x <- intervalbig]
grid = pictures[line [(0,y),(x,50)] | x <- xlist, y <- ylist, x-y==2]
insidegrid = pictures[
translate 0 (-50) grid,
rotate 90 (translate 0 (-50) grid),
rotate 180 (translate 0 (-50) grid),
rotate 270 (translate 0 (-50) grid)]
drawpicture :: Float -> Picture
drawpicture number = pictures [
color red (pictures [circle 50,circle 8.5]),
line [(-50,-50),(-50,50),(50,50),(50,-50),(-50,-50)],
squares,
scale 0.7 0.7 squares,
scale 0.49 0.49 squares,
scale 0.347 0.347 squares,
scale 0.242 0.242 squares,
color orange stars,
color orange (scale 0.178 0.178 stars),
rotate 11.25 (scale 0.178 0.178 stars),
translate (-50) 0 grid,
rotate 90 (Translate (-50) 0 grid),
rotate 180 (Translate (-50) 0 grid),
rotate 270 (Translate (-50) 0 grid),
color orangered insidegrid,
color orangered2 (rotate 45 insidegrid),
color orangered3 (rotate 22.5 insidegrid),
color orangered3 (rotate 67.5 insidegrid)
]
It's easier if you have separate draw functions for each visual element, but the basic answer is: to animate it just use the animate function and rotate the image components you desire to "move":
import Graphics.Gloss
main = animate (InWindow "Gloss" (700,700) (0,0))
black picture
picture :: Float -> Picture
picture 0 = text "Value cannot be 0"
picture number = scale 6.5 6.5 (color rose $ drawpicture number)
orangered, orangered2, orangered3 :: Color
orangered = makeColor 1.0 0.251 0.0 0.7
orangered2 = makeColor 1.0 0.251 0.0 0.5
orangered3 = makeColor 1.0 0.251 0.0 0.3
intervalsmall = [0,11.25,22.5,33.75,45,56.25,67.5,78.75]
intervalbig = [0,22.5,45,67.5,90,112.5,135,157.5,180,202.5,225,247.5,270,292.5,315,337.5]
xlist = [2,4..50]
ylist = [0,2..48]
squares = pictures[rotate x (line [(-50,0),(0,50),(50,0),(0,-50),(-50,0)]) | x <- intervalsmall]
stars = pictures[rotate x ((pictures [line [(-8.5,0),(0,50),(8.5,0)],line[(0,50),(0,0)]])) | x <- intervalbig]
grid = pictures[line [(0,y),(x,50)] | x <- xlist, y <- ylist, x-y==2]
insidegrid = pictures[
translate 0 (-50) grid,
rotate 90 (translate 0 (-50) grid),
rotate 180 (translate 0 (-50) grid),
rotate 270 (translate 0 (-50) grid)]
rotVal :: Float -> Float
rotVal x = x - (x / (2*pi))
drawpicture :: Float -> Picture
drawpicture number = pictures [
rot $ color red (pictures [circle 50,circle 8.5]),
line [(-50,-50),(-50,50),(50,50),(50,-50),(-50,-50)],
rot $ squares,
rot $ scale 0.7 0.7 squares,
rot $ scale 0.49 0.49 squares,
rot $ scale 0.347 0.347 squares,
rot $ scale 0.242 0.242 squares,
rot $ color orange stars,
rot (color orange (scale 0.178 0.178 stars)),
rot (rotate 11.25 (scale 0.178 0.178 stars)),
translate (-50) 0 grid,
rotate 90 (Translate (-50) 0 grid),
rotate 180 (Translate (-50) 0 grid),
rotate 270 (Translate (-50) 0 grid),
rot $ color orangered insidegrid,
rot $ color orangered2 (rotate 45 insidegrid),
rot $ color orangered3 (rotate 22.5 insidegrid),
rot $ color orangered3 (rotate 67.5 insidegrid)
]
where rot = rotate (rotVal number)
It is too much to write out all for you but you just have to add another argument to your picture function that is a Float and represents time. So display would be replaced by animate. So.
main = animate (InWindow "Gloss" (700,700) (0,0))
black (picture 100)
picture :: Float -> Float -> Picture
picture number time = -- whatever you have to do
You'll have to change your helping drawing functions to take this time param. Let's say you want to rotate the whole think once ever 5 seconds you can just multiply this time coming in and get an angle angle = time*(pi*2/5) then you can use this angle for trig functions to calculate new x and y positions from the center.

Resources