346 lines
12 KiB
Plaintext
346 lines
12 KiB
Plaintext
|
{
|
||
|
"cells": [
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": 1,
|
||
|
"metadata": {
|
||
|
"metadata": {}
|
||
|
},
|
||
|
"outputs": [],
|
||
|
"source": [
|
||
|
"import cv2\n",
|
||
|
"import numpy as np\n",
|
||
|
"import os\n",
|
||
|
"\n",
|
||
|
"INTERVV = [0.09, 0.29, 0.5, 0.7, 0.91]\n",
|
||
|
"INTERVH = [0.33, 0.6]\n"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": 2,
|
||
|
"metadata": {
|
||
|
"metadata": {}
|
||
|
},
|
||
|
"outputs": [],
|
||
|
"source": [
|
||
|
"def draw_interactive_polygon(image_path):\n",
|
||
|
" # Initialize variables\n",
|
||
|
" points = []\n",
|
||
|
" moving = False\n",
|
||
|
" current_point_index = -1\n",
|
||
|
"\n",
|
||
|
" original_image = cv2.flip(cv2.imread(image_path), 1)\n",
|
||
|
" image = original_image.copy()\n",
|
||
|
" window_name = \"Polygon Drawer\"\n",
|
||
|
"\n",
|
||
|
" def interpolate(p1, p2, t):\n",
|
||
|
" \"\"\"Linearly interpolate between points p1 and p2 with parameter t\"\"\"\n",
|
||
|
" return [int((1 - t) * p1[0] + t * p2[0]), int((1 - t) * p1[1] + t * p2[1])]\n",
|
||
|
"\n",
|
||
|
" def draw_additional_lines(temp_image, points):\n",
|
||
|
" \"\"\"Draw lines between interpolated points on the first, third, second, and fourth edges\"\"\"\n",
|
||
|
" if len(points) == 4:\n",
|
||
|
" # Intervals for the first-third edge connection\n",
|
||
|
" edge1_points = [interpolate(points[0], points[1], t) for t in INTERVV]\n",
|
||
|
" edge3_points = [interpolate(points[2], points[3], 1 - t) for t in INTERVV]\n",
|
||
|
" for p1, p3 in zip(edge1_points, edge3_points):\n",
|
||
|
" cv2.line(temp_image, tuple(p1), tuple(p3), (0, 255, 255), 1)\n",
|
||
|
"\n",
|
||
|
" # Intervals for the second-fourth edge connection\n",
|
||
|
" edge2_points = [interpolate(points[1], points[2], t) for t in INTERVH]\n",
|
||
|
" edge4_points = [interpolate(points[3], points[0], 1 - t) for t in INTERVH]\n",
|
||
|
" for p2, p4 in zip(edge2_points, edge4_points):\n",
|
||
|
" cv2.line(temp_image, tuple(p2), tuple(p4), (255, 0, 255), 1)\n",
|
||
|
" return temp_image\n",
|
||
|
"\n",
|
||
|
" def draw_polygon(temp_image, points, closed=False):\n",
|
||
|
" if len(points) > 1:\n",
|
||
|
" color = (0, 255, 0) if not closed else (255, 0, 0)\n",
|
||
|
" cv2.polylines(temp_image, [np.array(points, np.int32)], closed, color, 2)\n",
|
||
|
" for point in points:\n",
|
||
|
" cv2.circle(temp_image, tuple(point), 5, (0, 0, 255), -1)\n",
|
||
|
" temp_image = draw_additional_lines(temp_image, points)\n",
|
||
|
" return temp_image\n",
|
||
|
"\n",
|
||
|
" def mouse_events(event, x, y, flags, param):\n",
|
||
|
" nonlocal points, moving, current_point_index, image, original_image\n",
|
||
|
" if event == cv2.EVENT_LBUTTONDOWN:\n",
|
||
|
" for i, point in enumerate(points):\n",
|
||
|
" if abs(x - point[0]) < 5 and abs(y - point[1]) < 5:\n",
|
||
|
" moving = True\n",
|
||
|
" current_point_index = i\n",
|
||
|
" return\n",
|
||
|
" if len(points) < 4:\n",
|
||
|
" points.append([x, y])\n",
|
||
|
" image = draw_polygon(\n",
|
||
|
" original_image.copy(), points, closed=(len(points) == 4)\n",
|
||
|
" )\n",
|
||
|
"\n",
|
||
|
" elif event == cv2.EVENT_MOUSEMOVE:\n",
|
||
|
" if moving and current_point_index != -1:\n",
|
||
|
" points[current_point_index] = [x, y]\n",
|
||
|
" image = draw_polygon(\n",
|
||
|
" original_image.copy(), points, closed=(len(points) == 4)\n",
|
||
|
" )\n",
|
||
|
"\n",
|
||
|
" elif event == cv2.EVENT_LBUTTONUP:\n",
|
||
|
" moving = False\n",
|
||
|
" current_point_index = -1\n",
|
||
|
"\n",
|
||
|
" cv2.namedWindow(window_name)\n",
|
||
|
" cv2.setMouseCallback(window_name, mouse_events)\n",
|
||
|
"\n",
|
||
|
" # Main loop\n",
|
||
|
" while True:\n",
|
||
|
" cv2.imshow(window_name, image)\n",
|
||
|
" key = cv2.waitKey(1) & 0xFF\n",
|
||
|
" if key == 13: # Enter key\n",
|
||
|
" cv2.destroyAllWindows()\n",
|
||
|
" return points # Return the coordinates when Enter is pressed\n"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": 3,
|
||
|
"metadata": {
|
||
|
"metadata": {}
|
||
|
},
|
||
|
"outputs": [],
|
||
|
"source": [
|
||
|
"def warp_polygon(image_path, polygon_points):\n",
|
||
|
" \"\"\"Warps the quadrilateral defined by polygon_points into a rectangle.\"\"\"\n",
|
||
|
"\n",
|
||
|
" image = cv2.imread(image_path)\n",
|
||
|
" image = cv2.flip(image, 1)\n",
|
||
|
"\n",
|
||
|
" pts_src = np.array(polygon_points).astype(np.float32)\n",
|
||
|
"\n",
|
||
|
" # Define points in destination (output rectangle) image\n",
|
||
|
" width = 200 # Width of the rectangle\n",
|
||
|
" height = 50 # Height of the rectangle\n",
|
||
|
" pts_dst = np.array(\n",
|
||
|
" [[0, 0], [width - 1, 0], [width - 1, height - 1], [0, height - 1]]\n",
|
||
|
" ).astype(np.float32)\n",
|
||
|
"\n",
|
||
|
" # Calculate the perspective transform matrix\n",
|
||
|
" matrix = cv2.getPerspectiveTransform(pts_src, pts_dst)\n",
|
||
|
"\n",
|
||
|
" # Warp the image\n",
|
||
|
" warped_image = cv2.warpPerspective(image, matrix, (width, height))\n",
|
||
|
" return warped_image\n",
|
||
|
"\n",
|
||
|
"\n",
|
||
|
"def extract_line_pixels(warped_image, intervalsV, intervalsH):\n",
|
||
|
" \"\"\"Extracts pixel data along vertical and horizontal lines at given intervals.\"\"\"\n",
|
||
|
" height, width, channels = warped_image.shape\n",
|
||
|
"\n",
|
||
|
" pixel_data = []\n",
|
||
|
"\n",
|
||
|
" # Vertical lines\n",
|
||
|
" for i in intervalsV:\n",
|
||
|
" x_coord = int(width * i)\n",
|
||
|
" vertical_line = warped_image[:, x_coord, 1]\n",
|
||
|
" pixel_data.append(vertical_line)\n",
|
||
|
"\n",
|
||
|
" # Horizontal lines\n",
|
||
|
" for i in intervalsH:\n",
|
||
|
" y_coord = int(height * i)\n",
|
||
|
" horizontal_line = warped_image[y_coord, :, 1]\n",
|
||
|
" pixel_data.append(horizontal_line)\n",
|
||
|
"\n",
|
||
|
" return pixel_data\n"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {
|
||
|
"metadata": {}
|
||
|
},
|
||
|
"source": [
|
||
|
"import matplotlib.pyplot as plt\n",
|
||
|
"\n",
|
||
|
"fig, axes = plt.subplots(3, 5, figsize=(15, 15))\n",
|
||
|
"axes = axes.flatten()\n",
|
||
|
"for i, pixels in enumerate(data):\n",
|
||
|
"axes[i].plot(pixels)\n",
|
||
|
"axes[i].set_ylim([0, 255])\n",
|
||
|
"axes[i].set_title(f\"Line {i+1}\")\n",
|
||
|
"axes[i].set_xlabel(\"Pixel Index\")\n",
|
||
|
"axes[i].set_ylabel(\"Pixel Value\")\n",
|
||
|
"\n",
|
||
|
"plt.tight_layout()\n"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": 4,
|
||
|
"metadata": {
|
||
|
"metadata": {}
|
||
|
},
|
||
|
"outputs": [],
|
||
|
"source": [
|
||
|
"def peaks(data, boxes=2):\n",
|
||
|
" # split data in boxes\n",
|
||
|
" data = np.array_split(data, boxes)\n",
|
||
|
"\n",
|
||
|
" # get the maximum value in each box\n",
|
||
|
" data = [np.max(d) for d in data]\n",
|
||
|
" data = [d > 150 for d in data]\n",
|
||
|
" return np.array(data).astype(int).tolist()\n",
|
||
|
"\n",
|
||
|
"\n",
|
||
|
"digits = {\n",
|
||
|
" 0: [[1, 0, 1], [1, 1], [1, 1]],\n",
|
||
|
" 1: [[0, 0, 0], [0, 1], [0, 1]],\n",
|
||
|
" 2: [[1, 1, 1], [0, 1], [1, 0]],\n",
|
||
|
" 3: [[1, 1, 1], [0, 1], [0, 1]],\n",
|
||
|
" 4: [[0, 1, 0], [1, 1], [0, 1]],\n",
|
||
|
" 5: [[1, 1, 1], [1, 0], [0, 1]],\n",
|
||
|
" 6: [[1, 1, 1], [1, 0], [1, 1]],\n",
|
||
|
" 7: [[1, 0, 0], [0, 1], [0, 1]],\n",
|
||
|
" 8: [[1, 1, 1], [1, 1], [1, 1]],\n",
|
||
|
" 9: [[1, 1, 1], [1, 1], [0, 1]],\n",
|
||
|
"}\n",
|
||
|
"\n",
|
||
|
"\n",
|
||
|
"def OCRdigit(vertical, horizontal1, horizontal2):\n",
|
||
|
" # get times it goes above 150, remove subsequent values\n",
|
||
|
" digit = [peaks(vertical, 3), peaks(horizontal1), peaks(horizontal2)]\n",
|
||
|
" digit = [key for key, value in digits.items() if value == digit]\n",
|
||
|
" return digit[0]\n",
|
||
|
"\n",
|
||
|
"\n",
|
||
|
"def OCRscreen(pixels_along_lines):\n",
|
||
|
" data = (\n",
|
||
|
" pixels_along_lines[:5]\n",
|
||
|
" + [\n",
|
||
|
" pixels_along_lines[5][:40],\n",
|
||
|
" pixels_along_lines[5][40:80],\n",
|
||
|
" pixels_along_lines[5][80:120],\n",
|
||
|
" pixels_along_lines[5][120:160],\n",
|
||
|
" pixels_along_lines[5][160:],\n",
|
||
|
" ]\n",
|
||
|
" + [\n",
|
||
|
" pixels_along_lines[6][:40],\n",
|
||
|
" pixels_along_lines[6][40:80],\n",
|
||
|
" pixels_along_lines[6][80:120],\n",
|
||
|
" pixels_along_lines[6][120:160],\n",
|
||
|
" pixels_along_lines[6][160:],\n",
|
||
|
" ]\n",
|
||
|
" )\n",
|
||
|
"\n",
|
||
|
" text = \"\"\n",
|
||
|
" for i in range(5):\n",
|
||
|
" text += str(OCRdigit(data[i], data[i + 5], data[i + 10]))\n",
|
||
|
" return text\n"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": 5,
|
||
|
"metadata": {
|
||
|
"metadata": {}
|
||
|
},
|
||
|
"outputs": [],
|
||
|
"source": [
|
||
|
"from datetime import datetime\n",
|
||
|
"import xlsxwriter\n",
|
||
|
"\n",
|
||
|
"\n",
|
||
|
"def writeDate(worksheet, row, column, date, format):\n",
|
||
|
" original_format = \"%Y-%m-%d %H-%M-%S-%f\"\n",
|
||
|
" parsed_datetime = datetime.strptime(date, original_format)\n",
|
||
|
"\n",
|
||
|
" worksheet.write_datetime(row, column, parsed_datetime, format)\n",
|
||
|
"\n",
|
||
|
"\n",
|
||
|
"def data2excel(data):\n",
|
||
|
" # save the data in an excel file\n",
|
||
|
" fileName = \"data.xlsx\"\n",
|
||
|
" workbook = xlsxwriter.Workbook(fileName)\n",
|
||
|
" worksheet = workbook.add_worksheet()\n",
|
||
|
"\n",
|
||
|
" dateFormat = workbook.add_format({\"num_format\": \"dd/mm/yy hh:mm:ss\"})\n",
|
||
|
"\n",
|
||
|
" # write the data\n",
|
||
|
" row = 0\n",
|
||
|
" for key, value in data.items():\n",
|
||
|
" date = key.split(\" \", 1)[1][:-4]\n",
|
||
|
" writeDate(worksheet, row, 0, date, dateFormat)\n",
|
||
|
" worksheet.write(row, 1, value)\n",
|
||
|
" try:\n",
|
||
|
" worksheet.write(row, 2, float(value[:6]))\n",
|
||
|
" except Exception as _:\n",
|
||
|
" pass\n",
|
||
|
" row += 1\n",
|
||
|
"\n",
|
||
|
" workbook.close()\n"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": 10,
|
||
|
"metadata": {
|
||
|
"metadata": {}
|
||
|
},
|
||
|
"outputs": [
|
||
|
{
|
||
|
"name": "stdout",
|
||
|
"output_type": "stream",
|
||
|
"text": [
|
||
|
"Error processing bandicam 2024-04-16 11-25-10-700.jpg: list index out of range\n",
|
||
|
"Error processing bandicam 2024-04-16 11-40-00-733.jpg: list index out of range\n",
|
||
|
"Error processing bandicam 2024-04-16 11-40-10-720.jpg: list index out of range\n",
|
||
|
"Error processing bandicam 2024-04-16 11-44-30-732.jpg: list index out of range\n",
|
||
|
"Error processing bandicam 2024-04-16 11-48-20-723.jpg: list index out of range\n",
|
||
|
"Error processing bandicam 2024-04-16 11-48-30-728.jpg: list index out of range\n",
|
||
|
"Error processing bandicam 2024-04-16 11-49-50-741.jpg: list index out of range\n"
|
||
|
]
|
||
|
}
|
||
|
],
|
||
|
"source": [
|
||
|
"folder = (\n",
|
||
|
" \"./2/\"\n",
|
||
|
")\n",
|
||
|
"images = [f for f in os.listdir(folder) if f.endswith(\".jpg\")]\n",
|
||
|
"\n",
|
||
|
"region = draw_interactive_polygon(folder + images[0])\n",
|
||
|
"\n",
|
||
|
"data = {}\n",
|
||
|
"for image in images:\n",
|
||
|
" try:\n",
|
||
|
" warped = warp_polygon(folder + image, region)\n",
|
||
|
" pixels_along_lines = extract_line_pixels(warped, INTERVV, INTERVH)\n",
|
||
|
" data[image] = OCRscreen(pixels_along_lines)\n",
|
||
|
" except Exception as e:\n",
|
||
|
" print(f\"Error processing {image}: {e}\")\n",
|
||
|
" continue\n",
|
||
|
"\n",
|
||
|
"data2excel(data)\n"
|
||
|
]
|
||
|
}
|
||
|
],
|
||
|
"metadata": {
|
||
|
"kernelspec": {
|
||
|
"display_name": "AI_logging",
|
||
|
"language": "python",
|
||
|
"name": "python3"
|
||
|
},
|
||
|
"language_info": {
|
||
|
"codemirror_mode": {
|
||
|
"name": "ipython",
|
||
|
"version": 3
|
||
|
},
|
||
|
"file_extension": ".py",
|
||
|
"mimetype": "text/x-python",
|
||
|
"name": "python",
|
||
|
"nbconvert_exporter": "python",
|
||
|
"pygments_lexer": "ipython3",
|
||
|
"version": "3.10.14"
|
||
|
}
|
||
|
},
|
||
|
"nbformat": 4,
|
||
|
"nbformat_minor": 2
|
||
|
}
|