Skip to content

Instantly share code, notes, and snippets.

@andland
Last active January 1, 2017 13:43
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save andland/efe66240184328f07429 to your computer and use it in GitHub Desktop.
Save andland/efe66240184328f07429 to your computer and use it in GitHub Desktop.
Time Stack and Time Slicing

See this link for an introduction on time stacking and time slicing.

time_slice.R requires the number of pixels wide or tall the image is to be a multiple of the number of images in your timelapse.

time_slice_v2.R attempts to get around this. Some images will contribute more pixels per slice than others. This is done by making the first x% of the images cover the first x% of the pixels (with appropriate rounding). It does not deal with number of images being greater than the height or width of the images in pixels. Version 2 will probably work better for you.

For example, if the images are 150 pixels wide and your timelapse has 100 images, time_slice.R will make the first image have a slice which is 51 pixels wide. The remaining 99 images will get slices which are 1 pixel wide. time_slice_v2.R will alternate between 1 pixel per image and 2 pixels per image. All of the odd numbered images will get 1 pixel and all of the even numbered images will get 2 pixels. I haven't tested it out enough to tell if this causes any weird undesired (or desired) effects.

Time Slice Lapse

time_slice_lapse.R creates a time lapse out of time slices. (It actually creates the images necessary to create a time lapse. You still have to combine them into a movie.)

There are five options. As before, you can choose the direction. Then I split the path into source_path and save_path. The source_path is where the original images are saved. The save_path is where you want to save the time_slices, which will be used to create a time lapse.

The two new options are images_per_slice and num_of_slices. images_per_slice controls how many images make up each slice and num_of_slices controls how many slices will be in the time lapse. You probably want to use the default for the num_of_slices (i.e. use all of the available images). For images_per_slice, you can probably get different results based on this. The larger this is, the more time passes with a slice, but the fewer available slices for a time lapse. images_per_slice must be less than the number of pixels wide or tall.

I tried it out on a small example and it seems to work. I used only 10 images_per_slice which resulted in 36 total slices. It is posted here.

License

The code I have written is licensed MIT. Copyright Andrew Landgraf.

library(jpeg)
direction = "E" # in c("N", "S", "E", "W")
# make sure the path ends with a '/'
path = "enter/path/here/"
# this gets all the files in the folder that end in JPG or JPEG
files = list.files(path)
files = files[(toupper(substring(files, nchar(files) - 3)) == ".JPG" |
toupper(substring(files, nchar(files) - 4)) == ".JPEG")]
baseimg = readJPEG(paste0(path, files[1]))
# extra_pixels gives the first frame the extra pixels due to rounding
if (direction %in% c("E", "W")) {
num_pixels = floor(dim(baseimg)[2] / length(files))
extra_pixels = dim(baseimg)[2] - num_pixels * length(files)
} else if (direction %in% c("N", "S")) {
num_pixels = floor(dim(baseimg)[1] / length(files))
extra_pixels = dim(baseimg)[1] - num_pixels * length(files)
}
horiz = 1:dim(baseimg)[2]
vert = 1:dim(baseimg)[1]
for (i in 2:length(files)) {
cat(i, "of", length(files), "\n")
newimg = readJPEG(paste0(path, files[i]))
if (direction == "E") {
horiz = (num_pixels * (i - 1) + 1):(num_pixels * i) + extra_pixels
} else if (direction == "W") {
horiz = dim(baseimg)[2] - (num_pixels * (i - 1)):(num_pixels * i - 1) - extra_pixels
} else if (direction == "N") {
vert = dim(baseimg)[1] - (num_pixels * (i - 1)):(num_pixels * i - 1) - extra_pixels
} else if (direction == "S") {
vert = (num_pixels * (i - 1) + 1):(num_pixels * i) + extra_pixels
}
baseimg[vert, horiz, ] = newimg[vert, horiz, ]
}
writeJPEG(baseimg, paste0(path, "TimeSlice-", direction, ".JPG"), 1)
library(jpeg)
direction = "E" # in c("N", "S", "E", "W")
# make sure the paths end with a '/'
source_path = "path/to/original/images/"
save_path = "path/to/where/to/save/slices/"
files = list.files(source_path)
# get all of the images that end in .JPG or .JPEG
files = files[(toupper(substring(files, nchar(files) - 3)) == ".JPG" |
toupper(substring(files, nchar(files) - 4)) == ".JPEG")]
images_per_slice = round(length(files) / 2)
num_of_slices = length(files) - images_per_slice + 1
for (slice_num in 1:num_of_slices) {
cat("Slice", slice_num, "of", num_of_slices, "\n")
first_img = slice_num
# last_img = images_per_slice + slice_num - 1
# assumes all images are the same dimensions as the first image
baseimg = readJPEG(paste0(source_path, files[first_img]))
height = dim(baseimg)[1]
width = dim(baseimg)[2]
# num_images = length(files)
# the slicing will use all the pixels in one dimension
if (direction %in% c("E", "W")) {
vert = 1:height
} else if (direction %in% c("N", "S")) {
horiz = 1:width
}
end_pixel = floor(ifelse(direction %in% c("E", "W"), width, height) / images_per_slice * 1)
for (i in 2:images_per_slice) {
cat(" - Image", i, "of", images_per_slice, "\n")
newimg = readJPEG(paste0(source_path, files[first_img + i - 1]))
begin_pixel = end_pixel + 1
end_pixel = floor(ifelse(direction %in% c("E", "W"), width, height) / images_per_slice * i)
if (direction == "E") {
horiz = begin_pixel:end_pixel
} else if (direction == "W") {
horiz = width - (begin_pixel:end_pixel) + 1
} else if (direction == "N") {
vert = height - (begin_pixel:end_pixel) + 1
} else if (direction == "S") {
vert = begin_pixel:end_pixel
}
baseimg[vert, horiz, ] = newimg[vert, horiz, ]
}
writeJPEG(baseimg, paste0(save_path, "TimeSlice-", direction, "-",
sprintf("%03d", slice_num), ".JPG"), 1)
rm(baseimg)
}
library(jpeg)
direction = "E" # in c("N", "S", "E", "W")
# make sure the path ends with a '/'
path = "enter/path/here/"
# this gets all the files in the folder that end in JPG or JPEG
files = list.files(path)
files = files[(toupper(substring(files, nchar(files) - 3)) == ".JPG" |
toupper(substring(files, nchar(files) - 4)) == ".JPEG")]
# assumes all images are the same dimensions as the first image
baseimg = readJPEG(paste0(path, files[1]))
height = dim(baseimg)[1]
width = dim(baseimg)[2]
num_images = length(files)
# the slicing will use all the pixels in one dimension
if (direction %in% c("E", "W")) {
vert = 1:height
} else if (direction %in% c("N", "S")) {
horiz = 1:width
}
end_pixel = floor(ifelse(direction %in% c("E", "W"), width, height) / num_images * 1)
for (i in 2:num_images) {
cat(i, "of", num_images, "\n")
newimg = readJPEG(paste0(path, files[i]))
begin_pixel = end_pixel + 1
end_pixel = floor(ifelse(direction %in% c("E", "W"), width, height) / num_images * i)
if (direction == "E") {
horiz = begin_pixel:end_pixel
} else if (direction == "W") {
horiz = width - (begin_pixel:end_pixel) + 1
} else if (direction == "N") {
vert = height - (begin_pixel:end_pixel) + 1
} else if (direction == "S") {
vert = begin_pixel:end_pixel
}
baseimg[vert, horiz, ] = newimg[vert, horiz, ]
}
writeJPEG(baseimg, paste0(path, "TimeSlice-", direction, ".JPG"), 1)
library(jpeg)
# make sure the path ends with a '/'
path = "enter/path/here/"
files = list.files(path)
files = files[(toupper(substring(files, nchar(files) - 3)) == ".JPG" |
toupper(substring(files, nchar(files) - 4)) == ".JPEG")]
baseimg = readJPEG(paste0(path, files[1]))
for (i in 2: length(files)) {
cat(i, "of", length(files), "\n")
newimg = readJPEG(paste0(path, files[i]))
for (d in 1:3) {
baseimg[, , d] = pmax(baseimg[, , d], newimg[, , d])
}
}
writeJPEG(baseimg, paste0(path, "TimeStack.JPG"), 1)
@pthiedeke
Copy link

Hi Andrew, Thanks so much for your scripts and descriptions, this is amazing stuff. I am new to code so am having a few teething issues. I have downloaded R and the scripts but am not able to get it working. Can you tell me the routine for importing images into time_slice_lapse.R once R is open ? Thanks again, Peter

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment