PaulX 发表于 2023-10-12 13:53:09

传统opencv分割多张票据

针对于票据或者是多个零配件等物体通过修改对应参数可以做到大部分近似矩形物体的分割
由于无法上传.ipynb文件,各位可以复制进jupyter内查看并debug代码
### 0.导入包 定义显示函数
{
"cells": [
{
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 0.导入包 定义显示函数"
   ]
},
{
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import cv2 as cv\n",
    "import numpy as np\n",
    "\n",
    "def show_img(img, win_name):\n",
    "\n",
    "    # cv.namedWindow(win_name, cv.WINDOW_NORMAL | cv.WINDOW_KEEPRATIO)\n",
    "\n",
    "    cv.imshow(win_name, img)\n",
    "    \n",
    "    cv.waitKey(0)\n",
    "    cv.destroyAllWindows()"
   ]
},
{
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.读取图片 转为灰度图 利用高斯模糊消除噪声"
   ]
},
{
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "img_path = './fapiao_test//2tickets_test3.jpg'\n",
    "img = cv.imread(img_path)\n",
    "img = cv.resize(img, (600, 900))\n",
    "show_img(img, 'img')\n",
    "\n",
    "gray = cv.cvtColor(img, cv.COLOR_RGB2GRAY)\n",
    "\n",
    "gray = cv.GaussianBlur(gray, (7, 7), 0)\n",
    "show_img(gray, 'gray')"
   ]
},
{
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2.使用边缘检测"
   ]
},
{
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "edged = cv.Canny(gray, 100, 200)\n",
    "show_img(edged, 'edged')"
   ]
},
{
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3.形态学操作 进行腐蚀膨胀进一步消除噪声"
   ]
},
{
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "kernel = np.ones((7, 7), np.uint8)\n",
    "morphed = cv.dilate(edged, kernel, iterations=3)\n",
    "morphed = cv.erode(morphed, kernel, iterations=3)\n",
    "show_img(morphed, 'morphed')"
   ]
},
{
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 4.寻找轮廓 并排序 找出其中最大的4个轮廓"
   ]
},
{
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "morphed_copy = morphed.copy()\n",
    "cnts, _ = cv.findContours(morphed_copy, cv.RETR_TREE, cv.CHAIN_APPROX_NONE)\n",
    "if len(cnts) is not 0:\n",
    "    cnts = sorted(cnts, key=cv.contourArea, reverse=True)[:4]\n",
    "    print(len(cnts))\n",
    "else:\n",
    "    print(\"Did not find contours\\n\")\n",
    "\n",
    "# for cnt in cnts:\n",
    "#   x, y, w, h = cv.boundingRect(cnt)\n",
    "#   print(x, y, w, h)\n",
    "#   print('box_area: ', w * h)\n"
   ]
},
{
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 5.将轮廓处理成矩形 在原图上裁剪"
   ]
},
{
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "for cnt in cnts:\n",
    "    # 用周长的0.1倍作为阈值,对轮廓做近似处理,使其变成一个矩形\n",
    "    epsilon = 0.1 * cv.arcLength(cnt, True)\n",
    "    approx = cv.approxPolyDP(cnt, epsilon, True)\n",
    "\n",
    "    ticket_copy = img.copy()\n",
    "    cv.drawContours(ticket_copy, , -1, (255, 0, 0), 2)\n",
    "    show_img(ticket_copy, 'ticket_copy')\n",
    "\n",
    "    # 获取透视变换的原坐标\n",
    "    if approx.shape is not 4:\n",
    "      print(\"Found a non-rect\\n\")\n",
    "      continue\n",
    "    src_coor = np.reshape(approx, (4, 2))\n",
    "    src_coor = np.float32(src_coor)\n",
    "\n",
    "    # 右上,左上,左下,右下 坐标\n",
    "    (tr, tl, bl, br) = src_coor\n",
    "    print(tl, tl, br, br)\n",
    "\n",
    "    x1,x2 = min(tl, br), max(tl, br)\n",
    "    y1,y2 = min(tl, br), max(tl, br)\n",
    "\n",
    "    img_result = img\n",
    "    show_img(img_result, 'img_result')\n",
    "\n",
    "    # # 计算宽\n",
    "    # w1 = np.sqrt((tr - tl) ** 2 + (tr - tl) ** 2)\n",
    "    # w2 = np.sqrt((br - bl) ** 2 + (br - bl) ** 2)\n",
    "    # # 求出比较大的w\n",
    "    # max_w = max(int(w1), int(w2))\n",
    "    # # 计算高\n",
    "    # h1 = np.sqrt((bl - tl) ** 2 + (bl - tl) ** 2)\n",
    "    # h2 = np.sqrt((br - tr) ** 2 + (br - tr) ** 2)\n",
    "    # # 求出比较大的h\n",
    "    # max_h = max(int(h1), int(h2))\n",
    "\n",
    "    # # 透视变换的目标坐标\n",
    "    # dst_coor = np.array([, , , ], dtype=np.float32)\n",
    "\n",
    "    # # 求转换矩阵\n",
    "    # trans_mat = cv.getPerspectiveTransform(src_coor, dst_coor)\n",
    "    # # 进行转换,将图中对应坐标的图片截取出来,并转换到dst_coor大小\n",
    "    # warped = cv.warpPerspective(img, trans_mat, (max_w, max_h))\n",
    "\n",
    "    # warped = cv.rotate(warped, cv.ROTATE_90_COUNTERCLOCKWISE)\n",
    "\n",
    "    # show_img(warped, 'result')"
   ]
}
],
"metadata": {
"kernelspec": {
   "display_name": "yolo-pose",
   "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.7.12"
},
"orig_nbformat": 4
},
"nbformat": 4,
"nbformat_minor": 2
}

页: [1]
查看完整版本: 传统opencv分割多张票据