Skip to content

Commit f3b555d

Browse files
No public description
PiperOrigin-RevId: 819359586
1 parent 72a9d9e commit f3b555d

3 files changed

Lines changed: 76 additions & 62 deletions

File tree

official/projects/waste_identification_ml/llm_applications/milk_pouch_detection/classify_images.py

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,20 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15+
# Copyright 2025 The TensorFlow Authors. All Rights Reserved.
16+
#
17+
# Licensed under the Apache License, Version 2.0 (the "License");
18+
# you may not use this file except in compliance with the License.
19+
# You may obtain a copy of the License at
20+
#
21+
# http://www.apache.org/licenses/LICENSE-2.0
22+
#
23+
# Unless required by applicable law or agreed to in writing, software
24+
# distributed under the License is distributed on an "AS IS" BASIS,
25+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
26+
# See the License for the specific language governing permissions and
27+
# limitations under the License.
28+
1529
"""Classifies images based on Image Classifier."""
1630

1731
import glob
@@ -27,10 +41,8 @@
2741

2842

2943
FLAGS = flags.FLAGS
30-
flags.DEFINE_string(
31-
"input_dir", "tempdir", "Directory containing image frames to process."
32-
)
33-
44+
INPUT_DIR = "input_images"
45+
CLASSIFICATION_DIR = "objects_for_classification"
3446

3547
# Path to the custom trained model for Image Classifier.
3648
IMAGE_CLASSIFIER_WEIGHTS = (
@@ -40,28 +52,33 @@
4052

4153

4254
def main(_) -> None:
43-
dairy_folder = os.path.join(FLAGS.input_dir, "dairy")
44-
other_folder = os.path.join(FLAGS.input_dir, "others")
45-
os.makedirs(dairy_folder, exist_ok=True)
46-
os.makedirs(other_folder, exist_ok=True)
55+
parent_dir = os.path.dirname(os.path.abspath(INPUT_DIR))
56+
predictions_dir = os.path.join(parent_dir, "predictions")
57+
58+
dairy_predictions = os.path.join(predictions_dir, "dairy")
59+
other_predictions = os.path.join(predictions_dir, "others")
60+
os.makedirs(dairy_predictions, exist_ok=True)
61+
os.makedirs(other_predictions, exist_ok=True)
4762

4863
classifier = models.ImageClassifier(
4964
model_path=IMAGE_CLASSIFIER_WEIGHTS,
5065
class_names=CLASS_NAMES,
5166
device="cuda" if torch.cuda.is_available() else "cpu",
5267
)
5368

54-
files = glob.glob(os.path.join(FLAGS.input_dir, "tempdir", "*"))
69+
files = glob.glob(
70+
os.path.join(INPUT_DIR, CLASSIFICATION_DIR, "*")
71+
)
5572
print(f"Found {len(files)} images to process...")
5673

5774
total_dairy_packets = 0
5875
for path in tqdm.tqdm(files):
5976
pred_class, _ = classifier.classify(path)
6077
if pred_class == "dairy":
6178
total_dairy_packets += 1
62-
shutil.move(path, os.path.join(dairy_folder, os.path.basename(path)))
79+
shutil.move(path, os.path.join(dairy_predictions, os.path.basename(path)))
6380
else:
64-
shutil.move(path, os.path.join(other_folder, os.path.basename(path)))
81+
shutil.move(path, os.path.join(other_predictions, os.path.basename(path)))
6582

6683
if __name__ == "__main__":
6784
app.run(main)

official/projects/waste_identification_ml/llm_applications/milk_pouch_detection/extract_objects.py

Lines changed: 26 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,20 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15+
# Copyright 2025 The TensorFlow Authors. All Rights Reserved.
16+
#
17+
# Licensed under the Apache License, Version 2.0 (the "License");
18+
# you may not use this file except in compliance with the License.
19+
# You may obtain a copy of the License at
20+
#
21+
# http://www.apache.org/licenses/LICENSE-2.0
22+
#
23+
# Unless required by applicable law or agreed to in writing, software
24+
# distributed under the License is distributed on an "AS IS" BASIS,
25+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
26+
# See the License for the specific language governing permissions and
27+
# limitations under the License.
28+
1529
"""Detects, segments, and saves objects from images in a directory.
1630
1731
This script initializes a computer vision pipeline to process images, identify
@@ -37,41 +51,24 @@
3751
warnings.filterwarnings("ignore", category=FutureWarning)
3852
warnings.filterwarnings("ignore", category=UserWarning)
3953

40-
# Path to the pre-trained weights for the Grounding DINO model.
54+
4155
GROUNDING_DINO_WEIGHTS = (
4256
"milk_pouch_project/grounding_dino_model/groundingdino_swint_ogc.pth"
4357
)
44-
45-
# Path to the configuration file for the Grounding DINO model.
4658
GROUNDING_DINO_CONFIG = (
4759
"milk_pouch_project/grounding_dino_model/GroundingDINO_SwinT_OGC.py"
4860
)
49-
50-
# Path to the pre-trained weights for the SAM2 model.
5161
SAM2_WEIGHTS = "milk_pouch_project/sam2_model/sam2.1_hiera_large.pt"
52-
53-
# Path to the configuration file for the SAM2 model.
5462
SAM2_CONFIG = "configs/sam2.1/sam2.1_hiera_l.yaml"
55-
56-
# Text prompt to use for object detection.
5763
TEXT_PROMPT = "packets"
58-
59-
# Name of the temporary directory to store cropped object images.
60-
TEMP_DIR = "tempdir"
61-
62-
# Path to save the output COCO dataset file.
64+
INPUT_DIR = "input_images"
65+
CLASSIFICATION_DIR = "objects_for_classification"
6366
COCO_OUTPUT_PATH = "coco_output.json"
6467

6568
# Minimum mask area as percentage of image.
6669
MIN_MASK_AREA_PERCENT = 1.0
6770

6871
FLAGS = flags.FLAGS
69-
flags.DEFINE_string(
70-
"input_dir",
71-
None,
72-
"Directory containing image frames to process.",
73-
required=True,
74-
)
7572
flags.DEFINE_string(
7673
"category_name",
7774
None,
@@ -81,13 +78,13 @@
8178

8279
def main(_) -> None:
8380
"""Runs the main object detection and extraction pipeline."""
84-
if not os.path.isdir(FLAGS.input_dir):
85-
raise ValueError(f"Input directory not found at '{FLAGS.input_dir}'")
81+
if not os.path.isdir(INPUT_DIR):
82+
raise ValueError(f"Input directory not found at '{INPUT_DIR}'")
8683

8784
# Check if COCO output should be created
8885
create_coco = FLAGS.category_name is not None
8986

90-
print("Initializing Vision and Llm Pipeline...")
87+
print("Initializing image extraction and classification...")
9188
try:
9289
pipeline = models.ObjectDetectionSegmentation(
9390
dino_config_path=GROUNDING_DINO_CONFIG,
@@ -104,7 +101,7 @@ def main(_) -> None:
104101
print("✅ Pipeline ready.")
105102

106103
# Create output directory
107-
output_dir = os.path.join(FLAGS.input_dir, TEMP_DIR)
104+
output_dir = os.path.join(INPUT_DIR, CLASSIFICATION_DIR)
108105
os.makedirs(output_dir, exist_ok=True)
109106

110107
# Initialize coco json file format only if category_name is provided
@@ -119,7 +116,7 @@ def main(_) -> None:
119116
print("No category name provided. Skipping COCO JSON creation.")
120117

121118
# Get all image files.
122-
all_files = glob.glob(os.path.join(FLAGS.input_dir, "*"))
119+
all_files = glob.glob(os.path.join(INPUT_DIR, "*"))
123120
image_extensions = (".jpg", ".jpeg", ".png", ".bmp")
124121
files = [f for f in all_files if f.lower().endswith(image_extensions)]
125122
files = natsort.natsorted(files)
@@ -141,12 +138,6 @@ def main(_) -> None:
141138
)
142139
continue
143140

144-
# Uncomment to filter bigger overlapping boxes.
145-
# filtered_results = pipeline.filter_boxes_keep_smaller(
146-
# results,
147-
# iou_threshold=0.95
148-
# )
149-
150141
image = results["image"]
151142
h, w = image.shape[:2]
152143
image_area = h * w
@@ -169,7 +160,7 @@ def main(_) -> None:
169160
try:
170161
masked_object = models_utils.extract_masked_object(image, mask, box)
171162
models_utils.save_masked_object(
172-
masked_object, file_path, idx, TEMP_DIR
163+
masked_object, file_path, idx, CLASSIFICATION_DIR
173164
)
174165
except (ValueError, SystemError, AttributeError, OSError) as e:
175166
print(
@@ -180,10 +171,7 @@ def main(_) -> None:
180171

181172
# Add annotation info to COCO output only if create_coco is True
182173
if create_coco:
183-
# Get the polygon points of masks.
184174
segmentation = models_utils.extract_largest_contour_segmentation(mask)
185-
186-
# coco bbox format
187175
bbox_width, bbox_height, area = models_utils.get_bbox_details(box)
188176

189177
# annotation key format in coco json
@@ -199,20 +187,18 @@ def main(_) -> None:
199187
],
200188
"area": int(area),
201189
"iscrowd": 0,
202-
"segmentation": (
203-
segmentation
204-
), # Optional: Add segmentation if you have it
190+
"segmentation": segmentation,
205191
}
206192
coco_output["annotations"].append(annotation_info)
207193
annotation_id_counter += 1
208194

209195
# Save COCO JSON file only if create_coco is True
210196
if create_coco:
211-
with open(os.path.join(FLAGS.input_dir, COCO_OUTPUT_PATH), "w") as f:
197+
with open(os.path.join(INPUT_DIR, COCO_OUTPUT_PATH), "w") as f:
212198
json.dump(coco_output, f, indent=4)
213199
print(f"\n✅ Processing complete. COCO JSON saved to '{COCO_OUTPUT_PATH}'.")
214200

215-
print(f"✅ Cropped images saved to '{TEMP_DIR}'.")
201+
print(f"✅ Cropped images saved to '{CLASSIFICATION_DIR}'.")
216202

217203

218204
if __name__ == "__main__":
Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,39 @@
11
#!/bin/bash
2+
3+
# Exit immediately if a command exits with a non-zero status.
4+
set -o errexit
5+
26
# --- Parse command-line arguments ---
37
while [[ "$#" -gt 0 ]]; do
48
case $1 in
5-
--input_dir=*) input_dir="${1#*=}"; shift ;;
9+
--gcs_path=*) gcs_path="${1#*=}"; shift ;;
610
*) echo "❌ Unknown parameter passed: $1"; exit 1 ;;
711
esac
812
done
913
# --- Check if required arguments were provided ---
10-
if [ -z "$input_dir" ]; then
11-
echo "❌ Error: --input_dir must be specified"
12-
echo "✅ Usage: ./run_pipeline.sh --input_dir=/path/to/images"
14+
if [ -z "$gcs_path" ]; then
15+
echo "❌ Error: --gcs_path must be specified"
16+
echo "✅ Usage: ./run_pipeline.sh --gcs_path=/path/to/images"
1317
exit 1
1418
fi
19+
1520
# --- Run pipeline ---
1621
echo "✅ Activating virtual environment..."
1722
source myenv/bin/activate
1823

19-
echo "🚀 Running detect_and_segment.py..."
20-
echo " Input directory: $input_dir"
21-
python3 extract_objects.py --input_dir="$input_dir"
24+
echo "🖨️ Copying images files from GCS bucket: $gcs_path"
25+
mkdir -p input_images
26+
gsutil -m cp "$gcs_path"* input_images/
2227

23-
echo "🧠 Running classify.py..."
24-
python3 classify_images.py --input_dir="$input_dir"
25-
echo "🧹 Deactivating virtual environment..."
28+
echo "🔎 Extracting objects from images..."
29+
python3 extract_objects.py
2630

31+
echo "🧠 Classifying objects"
32+
python3 classify_images.py
33+
34+
echo "🖨️ Moving predictions back to GCS bucket..."
35+
gsutil -m cp -r predictions/ "$gcs_path"
36+
37+
echo "🧹 Deactivating virtual environment..."
2738
deactivate
28-
echo "✅ Done."
39+
echo "✅ Done."

0 commit comments

Comments
 (0)