-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
codes for coco, clip video, bash scripts (#64)
adding helper scripts for labelling prep tasks
- Loading branch information
1 parent
f2b7e2a
commit 539ae9b
Showing
5 changed files
with
408 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
import argparse | ||
import cv2 | ||
from pathlib import Path | ||
from datetime import datetime | ||
|
||
|
||
def real_time_to_frame_number( | ||
real_time: datetime, video_fps: float, start_real_time: datetime | ||
) -> int: | ||
""" | ||
Convert a real-time timestamp to the corresponding frame number in a video. | ||
Parameters: | ||
real_time (datetime): The real-time timestamp. | ||
video_fps (float): Frames per second of the video. | ||
start_real_time (datetime): The starting real-time timestamp of the video. | ||
Returns: | ||
int: The corresponding frame number in the video. | ||
""" | ||
time_difference = real_time - start_real_time | ||
total_seconds = time_difference.total_seconds() | ||
return int(total_seconds * video_fps) | ||
|
||
|
||
def create_clip( | ||
input_file: str, start_frame: int, end_frame: int, output_file: str | ||
) -> None: | ||
""" | ||
Create a video clip from the input video file, starting from a specific frame | ||
and ending at another frame. | ||
Parameters: | ||
input_file (str): Path to the input video file. | ||
start_frame (int): Starting frame number. | ||
end_frame (int): Ending frame number. | ||
output_file (str): Path to the output video file to be created. | ||
Returns: | ||
None | ||
""" | ||
cap = cv2.VideoCapture(input_file) | ||
video_fps = cap.get(cv2.CAP_PROP_FPS) | ||
|
||
fourcc = cv2.VideoWriter_fourcc(*"avc1") | ||
out = cv2.VideoWriter( | ||
output_file, fourcc, video_fps, (int(cap.get(3)), int(cap.get(4))), isColor=True | ||
) | ||
|
||
cap.set(cv2.CAP_PROP_POS_FRAMES, start_frame) | ||
|
||
while cap.isOpened(): | ||
ret, frame = cap.read() | ||
if not ret or cap.get(cv2.CAP_PROP_POS_FRAMES) > end_frame: | ||
break | ||
|
||
out.write(frame) | ||
|
||
cap.release() | ||
out.release() | ||
cv2.destroyAllWindows() | ||
|
||
|
||
def argument_parser() -> argparse.Namespace: | ||
"""Parse command-line arguments for the script. | ||
Returns | ||
------- | ||
argparse.Namespace | ||
An object containing the parsed command-line arguments. | ||
The attributes of this object correspond to the defined | ||
command-line arguments in the script. | ||
""" | ||
|
||
parser = argparse.ArgumentParser() | ||
parser.add_argument( | ||
"--video_path", | ||
type=str, | ||
required=True, | ||
help="Location of video file.", | ||
) | ||
parser.add_argument( | ||
"--start_time", | ||
type=str, | ||
default="12:00:00", | ||
help="Start time in the format 'HH:MM:SS'.", | ||
) | ||
parser.add_argument( | ||
"--event_time", | ||
type=str, | ||
default="12:01:00", | ||
help="Event time in the format 'HH:MM:SS'.", | ||
) | ||
parser.add_argument( | ||
"--end_time", | ||
type=str, | ||
default="12:03:00", | ||
help="Time after the event in the format 'HH:MM:SS'.", | ||
) | ||
parser.add_argument( | ||
"--out_path", | ||
type=str, | ||
required=True, | ||
help="Location of video file.", | ||
) | ||
args = parser.parse_args() | ||
return args | ||
|
||
|
||
if __name__ == "__main__": | ||
args = argument_parser() | ||
|
||
input_file = args.video_path | ||
file_name = f"{Path(args.video_path).parent.stem}_" f"{Path(args.video_path).stem}_" | ||
|
||
start_real_time = datetime.strptime(args.start_time, "%H:%M:%S") | ||
event_time = datetime.strptime(args.event_time, "%H:%M:%S") | ||
after_event_time = datetime.strptime(args.end_time, "%H:%M:%S") | ||
|
||
# Convert event times to frame numbers | ||
cap = cv2.VideoCapture(args.video_path) | ||
video_fps = cap.get(cv2.CAP_PROP_FPS) | ||
start_frame = real_time_to_frame_number(start_real_time, video_fps, start_real_time) | ||
event_frame = real_time_to_frame_number(event_time, video_fps, start_real_time) | ||
after_event_frame = real_time_to_frame_number( | ||
after_event_time, video_fps, start_real_time | ||
) | ||
total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) | ||
cap.release() | ||
|
||
# Create pre-event clip | ||
pre_event_clip = f"{args.out_path}/{file_name}_pre_event.mp4" | ||
create_clip(args.video_path, start_frame, event_frame - 1, pre_event_clip) | ||
|
||
# Create event clip | ||
event_clip = f"{args.out_path}/{file_name}_event.mp4" | ||
create_clip(args.video_path, event_frame, after_event_frame - 1, event_clip) | ||
|
||
# Create post-event clip | ||
post_event_clip = f"{args.out_path}/{file_name}_post_event.mp4" | ||
create_clip(args.video_path, after_event_frame, total_frames - 1, post_event_clip) | ||
|
||
print("Clips created successfully!") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
import json | ||
import argparse | ||
|
||
|
||
def combine_coco(coco1: str, coco2: str) -> None: | ||
""" | ||
Combine two COCO format JSON files and save the combined data to a new file. | ||
Parameters: | ||
coco1 (str): Path to the first COCO format JSON file. | ||
coco2 (str): Path to the second COCO format JSON file. | ||
Returns: | ||
None | ||
""" | ||
# Load the contents of the first JSON file | ||
with open(coco1, "r") as file1: | ||
data1 = json.load(file1) | ||
|
||
# Load the contents of the second JSON file | ||
with open(coco2, "r") as file2: | ||
data2 = json.load(file2) | ||
|
||
# Calculate the offset for image and annotation IDs in the second dataset | ||
offset_image_id = max([image["id"] for image in data1["images"]]) | ||
offset_annotation_id = max( | ||
[annotation["id"] for annotation in data1["annotations"]] | ||
) | ||
|
||
# Update the image and annotation IDs in the second dataset | ||
for image in data2["images"]: | ||
image["id"] += offset_image_id | ||
for annotation in data2["annotations"]: | ||
annotation["id"] += offset_annotation_id | ||
annotation["image_id"] += offset_image_id | ||
|
||
# Combine the images and annotations from both datasets | ||
combined_images = data1["images"] + data2["images"] | ||
combined_annotations = data1["annotations"] + data2["annotations"] | ||
|
||
# Create a new COCO dataset dictionary | ||
combined_data = { | ||
"images": combined_images, | ||
"annotations": combined_annotations, | ||
"categories": data1["categories"], | ||
} | ||
|
||
# Extract filenames without extensions from input paths | ||
filename1 = coco1.split(".")[0] | ||
filename2 = coco2.split(".")[0] | ||
|
||
# Create a new filename for the combined JSON file | ||
combined_filename = f"{filename1}_{filename2}_combine.json" | ||
|
||
# Save the combined data to the new JSON file | ||
with open(combined_filename, "w") as combined_file: | ||
json.dump(combined_data, combined_file) | ||
|
||
|
||
def argument_parser() -> argparse.Namespace: | ||
""" | ||
Parse command-line arguments for the script. | ||
Returns | ||
------- | ||
argparse.Namespace | ||
An object containing the parsed command-line arguments. | ||
The attributes of this object correspond to the defined | ||
command-line arguments in the script. | ||
""" | ||
parser = argparse.ArgumentParser() | ||
|
||
parser.add_argument( | ||
"--coco_one_path", | ||
type=str, | ||
required=True, | ||
help="Path for the the first coco file to be combined", | ||
) | ||
parser.add_argument( | ||
"--coco_two_path", | ||
type=str, | ||
required=True, | ||
help="Path for the the second coco file to be combined", | ||
) | ||
return parser.parse_args() | ||
|
||
|
||
if __name__ == "__main__": | ||
args = argument_parser() | ||
|
||
combine_coco(args.coco_one_path, args.coco_two_path) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
import json | ||
import argparse | ||
from typing import Dict, Any | ||
|
||
|
||
def coco_conversion(json_file_path: str) -> None: | ||
""" | ||
Convert annotation data in a JSON format to COCO format. | ||
Parameters: | ||
json_file (str): Path to the input JSON file containing annotation data. | ||
Returns: | ||
None | ||
This function takes annotation data in a specific JSON format and converts it | ||
into COCO format, which is widely used for object detection datasets. | ||
Note: | ||
The function assumes that the input JSON data has a specific structure | ||
that includes image metadata and regions of interest. The JSON data used | ||
has been produced by VIA. | ||
""" | ||
|
||
# Load the JSON data | ||
with open(json_file_path, "r") as json_file: | ||
annotation_data = json.load(json_file) | ||
|
||
# Create COCO format data structures | ||
coco_data: Dict[str, Any] = { | ||
"info": {}, | ||
"licenses": [], | ||
"categories": [{"id": 1, "name": "crab", "supercategory": "animal"}], | ||
"images": [], | ||
"annotations": [], | ||
} | ||
|
||
# Iterate through each image and annotation | ||
image_id = 1 | ||
annotation_id = 1 | ||
for image_filename, image_info in annotation_data["_via_img_metadata"].items(): | ||
image_data: Dict[str, Any] = { | ||
"id": image_id, | ||
"width": 0, # Set the image width here | ||
"height": 0, # Set the image height here | ||
"file_name": image_info["filename"], | ||
} | ||
coco_data["images"].append(image_data) | ||
|
||
for region in image_info["regions"]: | ||
x, y, width, height = ( | ||
region["shape_attributes"]["x"], | ||
region["shape_attributes"]["y"], | ||
region["shape_attributes"]["width"], | ||
region["shape_attributes"]["height"], | ||
) | ||
|
||
annotation_data = { | ||
"id": annotation_id, | ||
"image_id": image_id, | ||
"category_id": 1, | ||
"bbox": [x, y, width, height], | ||
"area": width * height, | ||
"iscrowd": 0, | ||
} | ||
coco_data["annotations"].append(annotation_data) | ||
annotation_id += 1 | ||
|
||
image_id += 1 | ||
|
||
# Write the COCO data to a JSON file | ||
new_file_name = f"{json_file_path.split('.')[0]}_coco.json" | ||
with open(new_file_name, "w") as f: | ||
json.dump(coco_data, f) | ||
|
||
|
||
def argument_parser() -> argparse.Namespace: | ||
""" | ||
Parse command-line arguments for the script. | ||
Returns | ||
------- | ||
argparse.Namespace | ||
An object containing the parsed command-line arguments. | ||
The attributes of this object correspond to the defined | ||
command-line arguments in the script. | ||
""" | ||
parser = argparse.ArgumentParser() | ||
|
||
parser.add_argument( | ||
"--json_path", | ||
type=str, | ||
required=True, | ||
help="Path for the json saved from VIA", | ||
) | ||
return parser.parse_args() | ||
|
||
|
||
if __name__ == "__main__": | ||
args = argument_parser() | ||
|
||
coco_conversion(args.json_path) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
#!/bin/bash | ||
|
||
#SBATCH -p gpu # partition | ||
#SBATCH -N 1 # number of nodes | ||
#SBATCH --mem 8G # memory pool for all cores | ||
#SBATCH -n 2 # number of cores | ||
#SBATCH -t 3-00:00 # time (D-HH:MM) | ||
#SBATCH --mail-type=ALL | ||
#SBATCH [email protected] | ||
|
||
# --------------------- | ||
# Load required modules | ||
# ---------------------- | ||
module load SLEAP | ||
|
||
# --------------------- | ||
# Define environment variables | ||
# ---------------------- | ||
# input/output dirs | ||
INPUT_DIR=/ceph/zoo/users/sminano/crabs_bboxes_labels/20230816_ramalhete2023_day2_combined/extracted_frames.json | ||
OUTPUT_DIR=/ceph/zoo/users/nikkna/event_clips/stacked_images/ | ||
|
||
# script location | ||
SCRATCH_PERSONAL_DIR=/ceph/scratch/nikkna | ||
SCRIPT_DIR=$SCRATCH_PERSONAL_DIR/crabs-exploration/"bboxes labelling" | ||
|
||
# TODO: set NUMEXPR_MAX_THREADS? | ||
# NumExpr detected 40 cores but "NUMEXPR_MAX_THREADS" not set, | ||
# so enforcing safe limit of 8. | ||
|
||
# ------------------- | ||
# Run python script | ||
# ------------------- | ||
python "$SCRIPT_DIR"/additional_channels_extraction.py \ | ||
--json_path $INPUT_DIR \ | ||
--out_dir $OUTPUT_DIR \;Q:q |
Oops, something went wrong.