Car_Damage_Analyses_Cost_Estimation / Damage_calculation.py
dharak003's picture
Upload 24 files
dba26ff verified
import os
from shapely.geometry import Polygon
class DamageCalculator:
def __init__(self):
self.cost_ranges = {
"Scratch": {
"Minor": (1000, 3000),
"Moderate": (3000, 5000),
"Severe": (5000, 10000)
},
"Dent": {
"Minor": (2000, 4000),
"Moderate": (4000, 10000),
"Severe": (10000, 15000)
},
"Paint chip": {
"Minor": (1000, 2000),
"Moderate": (2000, 4000),
"Severe": (4000, 10000)
},
"Broken part": (1000, 7000)
}
def parse_coordinates(self, file_path):
polygons = []
class_names = []
with open(file_path, 'r') as file:
for line in file:
parts = line.strip().split()
class_name = []
coordinates = []
for part in parts:
try:
coordinates.append(float(part))
except ValueError:
class_name.append(part)
if class_name and coordinates:
class_name = " ".join(class_name)
try:
if len(coordinates) % 2 != 0:
raise ValueError("Coordinates are not in pairs.")
polygon = Polygon([(coordinates[i], coordinates[i+1]) for i in range(0, len(coordinates), 2)])
polygons.append(polygon)
class_names.append(class_name)
except ValueError as e:
print(f"Skipping line due to error: {e}")
else:
print(f"Skipping line due to insufficient data: {line.strip()}")
return class_names, polygons
def calculate_severity(self, coverage_percentage):
if 3 < coverage_percentage <= 30:
return "Minor"
elif 30 < coverage_percentage <= 60:
return "Moderate"
elif coverage_percentage > 60:
return "Severe"
return "N/A"
def calculate_cost(self, damage_class, severity):
if damage_class == "Broken part":
return self.cost_ranges["Broken part"]
elif severity in self.cost_ranges[damage_class]:
return self.cost_ranges[damage_class][severity]
return (0, 0)
def summarize_damage_by_part(self, damage_polygons, part_polygons):
intersection_info = self.calculate_intersection_area(damage_polygons, part_polygons)
summary = {}
for info in intersection_info:
part_class = info['part_class']
damage_class = info['damage_class']
coverage_percentage = info['coverage_percentage']
if part_class not in summary:
summary[part_class] = {'total_coverage': 0, 'damage_types': {}}
summary[part_class]['total_coverage'] += coverage_percentage
if damage_class not in summary[part_class]['damage_types']:
summary[part_class]['damage_types'][damage_class] = 0
summary[part_class]['damage_types'][damage_class] += coverage_percentage
for part_class in summary:
total_coverage = summary[part_class]['total_coverage']
for damage_class in summary[part_class]['damage_types']:
summary[part_class]['damage_types'][damage_class] = (
summary[part_class]['damage_types'][damage_class] / total_coverage * 100
)
summary[part_class]['undamaged'] = 100 - total_coverage
return summary
def calculate_intersection_area(self, damage_polygons, part_polygons):
intersection_info = []
front_back_door_detected = any(part_class in ['Front-door', 'Back-door'] for part_class, _ in part_polygons)
for damage_class, damage_polygon in damage_polygons:
for part_class, part_polygon in part_polygons:
if damage_polygon.intersects(part_polygon):
intersection = damage_polygon.intersection(part_polygon)
intersection_area = intersection.area
part_area = part_polygon.area
coverage_percentage = (intersection_area / part_area) * 100
# Condition 1: Ignore damage coverage <= 3%
if coverage_percentage <= 3:
continue
# Condition 2: Apply weights based on the new conditions
if part_class in ['Front-bumper', 'Back-bumper']:
if front_back_door_detected:
coverage_percentage *= 0.2
else:
coverage_percentage *= 0.6
if coverage_percentage <= 3:
continue
# Updated Condition 3: Include Headlight and tail light only with broken part if damage > 50%
if part_class in ['Headlight', 'Tail-light']:
if damage_class == 'Broken part' and coverage_percentage > 50:
intersection_info.append({
"damage_class": damage_class,
"part_class": part_class,
"intersection_area": intersection_area,
"part_area": part_area,
"coverage_percentage": coverage_percentage
})
continue
# Condition 4: Exclude damage with front-wheel, back wheel, and license plate
if part_class in ['Front-wheel', 'Back-wheel', 'License-plate']:
continue
intersection_info.append({
"damage_class": damage_class,
"part_class": part_class,
"intersection_area": intersection_area,
"part_area": part_area,
"coverage_percentage": coverage_percentage
})
# Condition 5: Sum coverage for the same type of defect on the same part
summarized_info = {}
for info in intersection_info:
key = (info['damage_class'], info['part_class'])
if key not in summarized_info:
summarized_info[key] = {
"intersection_area": 0,
"part_area": info['part_area'],
"coverage_percentage": 0,
"count": 0
}
summarized_info[key]["intersection_area"] += info["intersection_area"]
summarized_info[key]["coverage_percentage"] += info["coverage_percentage"]
summarized_info[key]["count"] += 1
final_info = []
for (damage_class, part_class), values in summarized_info.items():
part_area = values["part_area"]
intersection_area = values["intersection_area"]
coverage_percentage = values["coverage_percentage"]
count = values["count"]
severity = self.calculate_severity(coverage_percentage)
cost_min, cost_max = self.calculate_cost(damage_class, severity)
final_info.append({
"damage_class": damage_class,
"part_class": part_class,
"intersection_area": intersection_area,
"part_area": part_area,
"coverage_percentage": coverage_percentage,
"severity": severity,
"cost_min": cost_min,
"cost_max": cost_max,
"count": count
})
return final_info