Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -422,7 +422,8 @@ class PolygonAugmentation:
|
|
| 422 |
if aug_type == "rotate":
|
| 423 |
# For rotation, use the parameter as degrees and make it more visible
|
| 424 |
rotation_angle = aug_param if abs(aug_param) >= 5 else (15 if aug_param >= 0 else -15)
|
| 425 |
-
|
|
|
|
| 426 |
logger.info(f"Applying rotation: {rotation_angle} degrees")
|
| 427 |
elif aug_type == "horizontal_flip":
|
| 428 |
aug_transform = A.HorizontalFlip(p=1.0 if aug_param == 1 else 0.0)
|
|
@@ -746,94 +747,124 @@ class PolygonAugmentation:
|
|
| 746 |
def create_download_package(self):
|
| 747 |
"""Create a zip file with all augmented images and proper LabelMe JSON files"""
|
| 748 |
if not self.augmented_results:
|
|
|
|
| 749 |
return None
|
| 750 |
|
|
|
|
| 751 |
zip_buffer = io.BytesIO()
|
| 752 |
|
| 753 |
-
|
| 754 |
-
|
| 755 |
-
|
| 756 |
-
|
| 757 |
-
|
| 758 |
-
|
| 759 |
-
|
| 760 |
-
|
| 761 |
-
|
| 762 |
-
|
| 763 |
-
|
| 764 |
-
|
| 765 |
-
|
| 766 |
-
|
| 767 |
-
|
| 768 |
-
|
| 769 |
-
|
| 770 |
-
|
| 771 |
-
|
| 772 |
-
|
| 773 |
-
|
| 774 |
-
|
| 775 |
-
|
| 776 |
-
|
| 777 |
-
|
| 778 |
-
|
| 779 |
-
|
| 780 |
-
|
| 781 |
-
|
| 782 |
-
|
| 783 |
-
|
| 784 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 785 |
|
| 786 |
-
|
| 787 |
-
|
| 788 |
-
|
| 789 |
-
|
| 790 |
-
|
| 791 |
-
|
| 792 |
-
|
| 793 |
-
|
| 794 |
-
'
|
| 795 |
-
|
| 796 |
-
|
| 797 |
-
|
| 798 |
-
|
| 799 |
-
|
| 800 |
-
|
| 801 |
-
|
| 802 |
-
|
| 803 |
-
|
| 804 |
-
|
| 805 |
-
|
| 806 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 807 |
}
|
| 808 |
-
for result in self.augmented_results
|
| 809 |
-
],
|
| 810 |
-
'statistics': {
|
| 811 |
-
'unique_augmentation_types': list(set([r['metadata']['augmentation_type'] for r in self.augmented_results])),
|
| 812 |
-
'total_polygons': sum([len(r['json_data']['shapes']) for r in self.augmented_results]),
|
| 813 |
-
'unique_labels': list(set([
|
| 814 |
-
shape['label']
|
| 815 |
-
for result in self.augmented_results
|
| 816 |
-
for shape in result['json_data']['shapes']
|
| 817 |
-
])),
|
| 818 |
-
'average_polygons_per_image': sum([len(r['json_data']['shapes']) for r in self.augmented_results]) / len(self.augmented_results)
|
| 819 |
}
|
| 820 |
-
|
| 821 |
-
|
| 822 |
-
|
| 823 |
-
|
| 824 |
-
readme_content = f"""# Augmented Dataset Package
|
| 825 |
|
| 826 |
## Overview
|
| 827 |
This package contains {len(self.augmented_results)} augmented images with their corresponding LabelMe annotation files.
|
| 828 |
|
| 829 |
## Contents
|
| 830 |
- **Images**: PNG format augmented images
|
| 831 |
-
- **Annotations**: LabelMe JSON format annotation files
|
| 832 |
- **Summary**: augmentation_summary.json with detailed metadata
|
| 833 |
|
| 834 |
## File Structure
|
| 835 |
- Each image file (*.png) has a corresponding annotation file (*.json) with the same base name
|
| 836 |
- All annotations are in standard LabelMe format without embedded image data
|
|
|
|
| 837 |
|
| 838 |
## Statistics
|
| 839 |
- Total augmented images: {len(self.augmented_results)}
|
|
@@ -849,11 +880,19 @@ This package contains {len(self.augmented_results)} augmented images with their
|
|
| 849 |
Generated on: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
|
| 850 |
Tool: PolygonAugmentation v1.0
|
| 851 |
"""
|
| 852 |
-
|
| 853 |
-
|
| 854 |
-
|
| 855 |
-
|
| 856 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 857 |
|
| 858 |
def create_interface():
|
| 859 |
augmenter = PolygonAugmentation(tolerance=2.0, area_threshold=0.01, debug=True)
|
|
@@ -957,7 +996,34 @@ def create_interface():
|
|
| 957 |
return [], error_msg, None
|
| 958 |
|
| 959 |
def download_package():
|
| 960 |
-
return
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 961 |
|
| 962 |
def show_mask_overlay(evt: gr.SelectData):
|
| 963 |
if evt.index < len(augmenter.augmented_results):
|
|
@@ -1042,7 +1108,7 @@ def create_interface():
|
|
| 1042 |
|
| 1043 |
with gr.Row():
|
| 1044 |
download_btn = gr.Button("📥 Download All (ZIP)", variant="secondary")
|
| 1045 |
-
download_file = gr.File(label="Download Package", visible=
|
| 1046 |
|
| 1047 |
gr.Markdown("## 📋 Augmentation Metadata")
|
| 1048 |
json_output = gr.Code(
|
|
|
|
| 422 |
if aug_type == "rotate":
|
| 423 |
# For rotation, use the parameter as degrees and make it more visible
|
| 424 |
rotation_angle = aug_param if abs(aug_param) >= 5 else (15 if aug_param >= 0 else -15)
|
| 425 |
+
# Use angle directly (not abs) and set limit as tuple for specific angle
|
| 426 |
+
aug_transform = A.Rotate(limit=(rotation_angle, rotation_angle), p=1.0, border_mode=cv2.BORDER_CONSTANT, value=0)
|
| 427 |
logger.info(f"Applying rotation: {rotation_angle} degrees")
|
| 428 |
elif aug_type == "horizontal_flip":
|
| 429 |
aug_transform = A.HorizontalFlip(p=1.0 if aug_param == 1 else 0.0)
|
|
|
|
| 747 |
def create_download_package(self):
|
| 748 |
"""Create a zip file with all augmented images and proper LabelMe JSON files"""
|
| 749 |
if not self.augmented_results:
|
| 750 |
+
logger.warning("No augmented results available for download")
|
| 751 |
return None
|
| 752 |
|
| 753 |
+
logger.info(f"Creating download package with {len(self.augmented_results)} results")
|
| 754 |
zip_buffer = io.BytesIO()
|
| 755 |
|
| 756 |
+
try:
|
| 757 |
+
with zipfile.ZipFile(zip_buffer, 'w', zipfile.ZIP_DEFLATED) as zip_file:
|
| 758 |
+
# Add all augmented images and their corresponding LabelMe JSON files
|
| 759 |
+
for idx, result in enumerate(self.augmented_results):
|
| 760 |
+
filename = result['metadata']['filename']
|
| 761 |
+
|
| 762 |
+
# Save augmented image
|
| 763 |
+
try:
|
| 764 |
+
# Convert PIL image to RGB if needed
|
| 765 |
+
if result['image'].mode != 'RGB':
|
| 766 |
+
img_rgb = result['image'].convert('RGB')
|
| 767 |
+
else:
|
| 768 |
+
img_rgb = result['image']
|
| 769 |
+
|
| 770 |
+
# Save as PNG bytes
|
| 771 |
+
img_buffer = io.BytesIO()
|
| 772 |
+
img_rgb.save(img_buffer, format='PNG', optimize=True)
|
| 773 |
+
zip_file.writestr(filename, img_buffer.getvalue())
|
| 774 |
+
logger.info(f"Added image: {filename}")
|
| 775 |
+
|
| 776 |
+
except Exception as e:
|
| 777 |
+
logger.error(f"Error saving image {filename}: {str(e)}")
|
| 778 |
+
continue
|
| 779 |
+
|
| 780 |
+
# Save corresponding LabelMe JSON file
|
| 781 |
+
json_filename = filename.replace('.png', '.json')
|
| 782 |
+
|
| 783 |
+
try:
|
| 784 |
+
# Create a clean LabelMe JSON structure
|
| 785 |
+
clean_json_data = {
|
| 786 |
+
"version": "5.0.1",
|
| 787 |
+
"flags": {},
|
| 788 |
+
"shapes": [],
|
| 789 |
+
"imagePath": filename,
|
| 790 |
+
"imageData": None, # No embedded image data as requested
|
| 791 |
+
"imageHeight": result['json_data']['imageHeight'],
|
| 792 |
+
"imageWidth": result['json_data']['imageWidth'],
|
| 793 |
+
"imageDepth": 3
|
| 794 |
+
}
|
| 795 |
+
|
| 796 |
+
# Copy shapes with proper LabelMe format
|
| 797 |
+
for shape in result['json_data']['shapes']:
|
| 798 |
+
clean_shape = {
|
| 799 |
+
"label": shape['label'],
|
| 800 |
+
"points": shape['points'],
|
| 801 |
+
"group_id": shape.get('group_id'),
|
| 802 |
+
"shape_type": "polygon",
|
| 803 |
+
"flags": shape.get('flags', {}),
|
| 804 |
+
"description": shape.get('description', ''),
|
| 805 |
+
"iscrowd": shape.get('iscrowd', 0),
|
| 806 |
+
"attributes": shape.get('attributes', {})
|
| 807 |
+
}
|
| 808 |
+
clean_json_data['shapes'].append(clean_shape)
|
| 809 |
+
|
| 810 |
+
# Write JSON file
|
| 811 |
+
json_str = json.dumps(clean_json_data, indent=2, ensure_ascii=False)
|
| 812 |
+
zip_file.writestr(json_filename, json_str)
|
| 813 |
+
logger.info(f"Added JSON: {json_filename} with {len(clean_json_data['shapes'])} shapes")
|
| 814 |
+
|
| 815 |
+
except Exception as e:
|
| 816 |
+
logger.error(f"Error saving JSON {json_filename}: {str(e)}")
|
| 817 |
+
continue
|
| 818 |
|
| 819 |
+
# Add comprehensive summary metadata
|
| 820 |
+
summary = {
|
| 821 |
+
'package_info': {
|
| 822 |
+
'total_augmentations': len(self.augmented_results),
|
| 823 |
+
'generation_timestamp': datetime.now().isoformat(),
|
| 824 |
+
'generator': 'PolygonAugmentation v1.0',
|
| 825 |
+
'format': 'LabelMe JSON + PNG images'
|
| 826 |
+
},
|
| 827 |
+
'augmentation_summary': [
|
| 828 |
+
{
|
| 829 |
+
'filename': result['metadata']['filename'],
|
| 830 |
+
'json_file': result['metadata']['filename'].replace('.png', '.json'),
|
| 831 |
+
'augmentation_type': result['metadata']['augmentation_type'],
|
| 832 |
+
'parameter_value': result['metadata']['parameter_value'],
|
| 833 |
+
'polygon_count': len(result['json_data']['shapes']),
|
| 834 |
+
'image_size': f"{result['json_data']['imageWidth']}x{result['json_data']['imageHeight']}",
|
| 835 |
+
'timestamp': result['metadata']['timestamp'],
|
| 836 |
+
'labels': list(set([shape['label'] for shape in result['json_data']['shapes']]))
|
| 837 |
+
}
|
| 838 |
+
for result in self.augmented_results
|
| 839 |
+
],
|
| 840 |
+
'statistics': {
|
| 841 |
+
'unique_augmentation_types': list(set([r['metadata']['augmentation_type'] for r in self.augmented_results])),
|
| 842 |
+
'total_polygons': sum([len(r['json_data']['shapes']) for r in self.augmented_results]),
|
| 843 |
+
'unique_labels': list(set([
|
| 844 |
+
shape['label']
|
| 845 |
+
for result in self.augmented_results
|
| 846 |
+
for shape in result['json_data']['shapes']
|
| 847 |
+
])),
|
| 848 |
+
'average_polygons_per_image': sum([len(r['json_data']['shapes']) for r in self.augmented_results]) / len(self.augmented_results) if self.augmented_results else 0
|
| 849 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 850 |
}
|
| 851 |
+
zip_file.writestr('augmentation_summary.json', json.dumps(summary, indent=2, ensure_ascii=False))
|
| 852 |
+
|
| 853 |
+
# Add README for the package
|
| 854 |
+
readme_content = f"""# Augmented Dataset Package
|
|
|
|
| 855 |
|
| 856 |
## Overview
|
| 857 |
This package contains {len(self.augmented_results)} augmented images with their corresponding LabelMe annotation files.
|
| 858 |
|
| 859 |
## Contents
|
| 860 |
- **Images**: PNG format augmented images
|
| 861 |
+
- **Annotations**: LabelMe JSON format annotation files (standard format)
|
| 862 |
- **Summary**: augmentation_summary.json with detailed metadata
|
| 863 |
|
| 864 |
## File Structure
|
| 865 |
- Each image file (*.png) has a corresponding annotation file (*.json) with the same base name
|
| 866 |
- All annotations are in standard LabelMe format without embedded image data
|
| 867 |
+
- Compatible with LabelMe, CVAT, and other annotation tools
|
| 868 |
|
| 869 |
## Statistics
|
| 870 |
- Total augmented images: {len(self.augmented_results)}
|
|
|
|
| 880 |
Generated on: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
|
| 881 |
Tool: PolygonAugmentation v1.0
|
| 882 |
"""
|
| 883 |
+
zip_file.writestr('README.md', readme_content)
|
| 884 |
+
|
| 885 |
+
logger.info("Successfully created ZIP package with all files")
|
| 886 |
+
|
| 887 |
+
zip_buffer.seek(0)
|
| 888 |
+
logger.info(f"Created download package with {len(self.augmented_results)} image-annotation pairs")
|
| 889 |
+
return zip_buffer.getvalue()
|
| 890 |
+
|
| 891 |
+
except Exception as e:
|
| 892 |
+
logger.error(f"Error creating ZIP package: {str(e)}")
|
| 893 |
+
import traceback
|
| 894 |
+
logger.error(traceback.format_exc())
|
| 895 |
+
return None
|
| 896 |
|
| 897 |
def create_interface():
|
| 898 |
augmenter = PolygonAugmentation(tolerance=2.0, area_threshold=0.01, debug=True)
|
|
|
|
| 996 |
return [], error_msg, None
|
| 997 |
|
| 998 |
def download_package():
|
| 999 |
+
"""Handle download package creation and return proper file data"""
|
| 1000 |
+
try:
|
| 1001 |
+
package_data = augmenter.create_download_package()
|
| 1002 |
+
if package_data is None:
|
| 1003 |
+
return None
|
| 1004 |
+
|
| 1005 |
+
# Save the package to a temporary file for download
|
| 1006 |
+
import tempfile
|
| 1007 |
+
import os
|
| 1008 |
+
|
| 1009 |
+
# Create temporary file with proper name
|
| 1010 |
+
temp_file = tempfile.NamedTemporaryFile(
|
| 1011 |
+
delete=False,
|
| 1012 |
+
suffix='.zip',
|
| 1013 |
+
prefix='augmented_dataset_'
|
| 1014 |
+
)
|
| 1015 |
+
|
| 1016 |
+
with open(temp_file.name, 'wb') as f:
|
| 1017 |
+
f.write(package_data)
|
| 1018 |
+
|
| 1019 |
+
logger.info(f"Created download package: {temp_file.name}")
|
| 1020 |
+
return temp_file.name
|
| 1021 |
+
|
| 1022 |
+
except Exception as e:
|
| 1023 |
+
logger.error(f"Error creating download package: {str(e)}")
|
| 1024 |
+
import traceback
|
| 1025 |
+
logger.error(traceback.format_exc())
|
| 1026 |
+
return None
|
| 1027 |
|
| 1028 |
def show_mask_overlay(evt: gr.SelectData):
|
| 1029 |
if evt.index < len(augmenter.augmented_results):
|
|
|
|
| 1108 |
|
| 1109 |
with gr.Row():
|
| 1110 |
download_btn = gr.Button("📥 Download All (ZIP)", variant="secondary")
|
| 1111 |
+
download_file = gr.File(label="Download Package", visible=True)
|
| 1112 |
|
| 1113 |
gr.Markdown("## 📋 Augmentation Metadata")
|
| 1114 |
json_output = gr.Code(
|