图像处理——边缘跟踪算法(Python)

边缘追踪算法

主要目的:实现目标物的框选,查找边缘
此处不涉及算子

处理步骤:

  1. 图像灰度化
  2. 图像二值化(处理好阈值——可优化,此处不涉及该研究)
  3. 找到起始点
  4. 从起始点开始边缘跟踪

算法核心:

设置好搜索方法(逆时针)

Direct = [(1, 0), (1, 1), (0, 1), (-1, 1), (-1, 0), (-1, -1), (0, -1), (1, -1)]

在这里插入图片描述
第一次搜索按照初始点的方向进行,这里需要清楚的是,获取初始点方向的方法

关于初始点的获取

  可以采取从左到右从上到下等方式,即获取的初始点必须是目标图像的顶点(上、下、左、右)
  不同的方向寻找的起点会使后面的搜索方法不同
  使用temp来作为方向的指示(数字代表的方向见上图中的黄色数字指示)
  这里使用查找方法为从上到下,从左到右,这里获取的是目标的左上角的点
  (使用上面的方法)令temp初始化:temp = 5 。通过起点的查找可以清楚的是目标物的左上方不存在目标物,因此最可能出现的点在左下方。顾为5。

关于搜索

  采用逆时针的循序,我们通过数字可以发现规律
  当temp = 5时,假设存在,即当前边缘中心(x,y)移动到temp= 5的方向,即初始(x,y) = (0,0),移动 ——> (x,y) = (-1,-1)
  我们向下一个点移动的时候相当于夹了一个180度的角,此时再进行搜索的时候需要回转90°,即变化temp的值。
  对此我们可以总结一条公式:
  当 temp 为 偶数 的时候:
     temp(new) = (temp + 7)% 8
  当 temp 为 奇数 的时候:
     temp(new) = (temp + 6)% 8

对于包围图像和非包围图像的提醒:

  在控制结束条件的时候需要注意的一点就是,包围图像的收尾为同一点,即当(x,y) = (startx, starty)时结束
  但当图像非包围图像时,需要控制条件进行,并且当图像进行分割时,左右两边可能需要再进行搜索,此处只拿特例,后续有更优化算法再更新。

# -*- coding = utf-8 -*-
# @Time : 2022/2/24 17:00
# @Author : Vinci
# @File : borad_find.py
# @Software: PyCharm

import cv2 as cv
import numpy as np


def get_binary_img(timg):
    bin_img = np.zeros(shape=timg.shape, dtype=np.uint8)
    h = timg.shape[0]  # 表示y的大小
    w = timg.shape[1]  # 表示x的大小
    # print(" h = {} w = {}".format(h,w))
    for i in range(h):  # 从上到下
        for j in range(w):
            bin_img[i][j] = 255 if timg[i][j] > 200 else 0
    return bin_img


def get_left_up_start_pt(flag, bin_img):
    h = bin_img.shape[0]
    w = bin_img.shape[1]
    find = 0
    start_y = 0
    start_x = 0
    if flag == 0:
        for j in range(h):  #从上到下
            for i in range(w):
                if bin_img[j][i] == 0:
                    find = 1
                    start_y = j
                    start_x = i
                    break
            if find == 1:
                break
    else:
        for j in range(h - 1, -1, -1):
            for i in range(w - 1, -1, -1):
                if bin_img[j][i] == 0:
                    find = 1
                    start_y = j
                    start_x = i
                    break
            if find == 1:
                break
    return find, start_x, start_y


def trace_contour(bin_img, find, start_i, start_j, contour_img):
    """
        物体(黑色) 为0
        背景(白色) 为255
    """
    flag = 0
    if find:
        contour_img[start_i][start_j] = 0

    Direct = [(1, 0), (1, 1), (0, 1), (-1, 1), (-1, 0), (-1, -1), (0, -1), (1, -1)]
    temp = 5
    if find == 2:
        temp = 1
    x, y = start_i, start_j
    while True:
        while True:
            tx = x + Direct[temp][1]
            ty = y + Direct[temp][0]
            if tx > bin_img.shape[1] - 1 or ty > bin_img.shape[0] - 1 or tx < 0 or ty < 0:
                temp += 1
                if temp == 8:
                    temp = 0
                continue
            if bin_img[ty][tx] == 0:
                contour_img[ty][tx] = 0
                if temp % 2 == 0:
                    temp = (temp + 7) % 8
                else:
                    temp = (temp + 6) % 8
                x = tx
                y = ty
                break
            temp += 1
            if temp == 8:
                temp = 0
        # print(x, y)
        if start_i == x and start_j == y:
            return flag, contour_img
        if x >= bin_img.shape[1] - 1 or y >= bin_img.shape[0] - 1 or x <= 0 or y <= 0:
            flag = 1
            return flag, contour_img


if __name__ == "__main__":
    img_name = "img/cap.png"
    img = cv.imread(img_name)
    gray_img = cv.cvtColor(img, cv.COLOR_BGR2GRAY)  # 转灰度图
    bin_img = get_binary_img(gray_img)  # 二值化

    # print(bin_img[370][360])   #需要注意的是图像转为数组的时候 x,y是反过来的
    # 边界追踪
    flag1 = 0
    find, start_i, start_j = get_left_up_start_pt(flag1, bin_img)
    # cv.circle(bin_img, (start_i, start_j), 3, (0, 0, 0), -1)
    # print("start_x, start_y = ", start_i, start_j)
    # cv.imshow("1", bin_img)

    contour_img = np.zeros(shape=bin_img.shape, dtype=np.uint8)
    contour_img += 255
    flag2, contour_img = trace_contour(bin_img, find, start_i, start_j, contour_img)

    if flag2 == 1:
        find1, start_i1, start_j1 = get_left_up_start_pt(flag2, bin_img)
        f, contour_img = trace_contour(bin_img, find1 + 1, start_i1, start_j1, contour_img)
        contour_img[0] = 255
        contour_img[len(contour_img) - 1] = 255
        for w in range(len(contour_img)):
            contour_img[w][0] = 255
            contour_img[w][len(contour_img[0]) - 1] = 255
    cv.imshow("img", contour_img)
    cv.waitKey()
    cv.destroyAllWindows()

在这里插入图片描述
在这里插入图片描述

  • 10
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
7.3.1 Suzuki–Kasami Algorithm This algorithm is defined for a completely connected network of processes. It assumes that initially an arbitrary process has the token. A process i that does not have the token but wants to enter its CS broadcasts a request (i, num), where num is sequence number of that request. The algorithm guarantees that eventually process i receives the token. Every process i maintains an array req[0.. n − 1] of integers, where req[j] designates the sequence number of the latest request received from process j. Note that although every process receives a request, only one process (which currently has the token) can grant the token. As a result, some pending requests become stale or outdated. An important issue in this algorithm is to identify and discard these stale requests. To accomplish this, each process uses the following two additional data structures that are passed on with the token by its current holder: • An array last[0.. n − 1] of integers, where last[k] = r implies that during its last visit to its CS, process k has completed its rth trip • A queue Q containing the identifiers of processes with pending requests When a process i receives a request with a sequence number num from process k, it updates req[k] to max(req[k], num), so that req[k] now represents the most recent request from process k. A process holding the token must guarantee (before passing it to another process) that its Q contains the most recent requests. To satisfy this requirement, when a process i receives a token from another process, it executes the following steps: • It copies its num into last[i]. • For each process k, process i retains process k’s name in its local queue Q only if 1 + last[k] = req[k] (this establishes that the request from process k is a recent one). • Process i completes the execution of its CS codes. • If Q is nonempty, then it forwards the token to the process at the head of Q after deleting its entry. To enter the CS, a process sends (n − 1) requests and receives one message containing the token. The total number of messages required to complete one visit to its CS is thus (n − 1) + 1 = n. Readers are referred to [SK85] for a proof of this algorithm理解Suzuki-Kasami算法,并回答如下问题: 算法是如何辨别和丢弃过时的请求的,或者说为什么要求1 + last[k] = req[k]?
最新发布
06-06
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值