最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

OpenCV圖像輪廓提取的實(shí)現(xiàn)

 更新時(shí)間:2022年08月08日 09:43:01   作者:cclplus  
本文主要介紹了OpenCV圖像輪廓提取的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

前言

常用的輪廓提取算法有:Canny、閾值分割、提取傅里葉變換的高頻信息,還有別具一格的蟻群算法,當(dāng)然比較常見的作法是使用閾值分割+邊緣查找,在OpenCV里是threshold和findContours兩個(gè)函數(shù)的組合使用,和Canny。

輪廓提取的算法很多,而其目的都是為了找到圖像中灰階差比較大的位置。而所謂亞像素提取,則是使用了插值算法,以找出灰階差最大的位置。

提取傅里葉變換的高頻信息

##############
#圖像中的輪廓提取
#時(shí)間:2019/1/3
#作者:cclplus
#僅供學(xué)習(xí)交流使用
#如有疑問或者需求,可以聯(lián)系作者的郵箱
#如果你有什么好的建議或者指導(dǎo),我將不勝感激


import cv2
import numpy as np
from matplotlib import pyplot as plt
import copy
img = cv2.imread('liuyifei.jpg',0)
f = np.fft.fft2(img)
fshift = np.fft.fftshift(f)

rows,cols = img.shape
crow,ccol = int(rows/2) , int(cols/2)
for i in range(crow-30,crow+30):
    for j in range(ccol-30,ccol+30):
        fshift[i][j]=0.0
f_ishift = np.fft.ifftshift(fshift)
img_back = np.fft.ifft2(f_ishift)#進(jìn)行高通濾波
# 取絕對值
img_back = np.abs(img_back)
plt.subplot(121),plt.imshow(img,cmap = 'gray')#因圖像格式問題,暫已灰度輸出
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
#先對灰度圖像進(jìn)行伽馬變換,以提升暗部細(xì)節(jié)
rows,cols = img_back.shape
gamma=copy.deepcopy(img_back)
rows=img.shape[0]
cols=img.shape[1]
for i in range(rows):
    for j in range(cols):
        gamma[i][j]=5.0*pow(gamma[i][j],0.34)#0.34這個(gè)參數(shù)是我手動(dòng)調(diào)出來的,根據(jù)不同的圖片,可以選擇不同的數(shù)值
#對灰度圖像進(jìn)行反轉(zhuǎn)

for i in range(rows):
    for j in range(cols):
        gamma[i][j]=255-gamma[i][j]
plt.subplot(122),plt.imshow(gamma,cmap = 'gray')
plt.title('Result in HPF'), plt.xticks([]), plt.yticks([])
plt.show()

原圖

在這里插入圖片描述

輸出結(jié)果

在這里插入圖片描述

通過蟻群算法進(jìn)行圖片輪廓提取

相關(guān)代碼我上傳到了我的github上
https://github.com/YuruTu/Ant_colony

在這里插入圖片描述

效果不夠理想,這也算得上蟻群算法的一大特點(diǎn),對參數(shù)要求較高,需要調(diào)參。相關(guān)內(nèi)容,筆者會(huì)持續(xù)更新

Canny邊緣檢測  

import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('liuyifei.jpg',0)
edges = cv2.Canny(img,100,200)

plt.subplot(121),plt.imshow(img,cmap='gray')
plt.title('original'),plt.xticks([]),plt.yticks([])
plt.subplot(122),plt.imshow(edges,cmap='gray')
plt.title('edge'),plt.xticks([]),plt.yticks([])

plt.show()

在這里插入圖片描述

使用cuda加速提取輪廓

#include <iostream>
#include <cuda.h>
#include <cstdlib>
#include <stdio.h>
#include <cuda_runtime.h>
#include <string>
#include <assert.h>
#include <cuda_runtime.h>
#include <cuda_runtime_api.h>
#include <device_launch_parameters.h>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>

using namespace cv;
using namespace std;
// GPU constant memory to hold our kernels (extremely fast access time)
__constant__ float convolutionKernelStore[256];

/**
 * Convolution funcion para cuda.  Destino tendra el mismo width/height como la fuente,
 *
 * @param source      Source imagen host
 * @param width       Source imagen width
 * @param height      Source imagen height
 * @param paddingX    source imagen padding x
 * @param paddingY    source imagen padding y
 * @param kOffset     offset en kernel almacenamiento de memoria constante
 * @param kWidth      kernel width
 * @param kHeight     kernel height
 * @param destination Imagen de destino
 */
__global__ void convolve(unsigned char *source, int width, int height, int paddingX, int paddingY, unsigned int kOffset, int kWidth, int kHeight, unsigned char *destination)
{
	// Calculate our pixel's location
	int x = (blockIdx.x * blockDim.x) + threadIdx.x;
	int y = (blockIdx.y * blockDim.y) + threadIdx.y;

	float sum = 0.0;
	int   pWidth = kWidth / 2;
	int   pHeight = kHeight / 2;

	//Solo ejecuta validos pixeles
	if (x >= pWidth + paddingX && y >= pHeight + paddingY && x < (blockDim.x * gridDim.x) - pWidth - paddingX &&
		y < (blockDim.y * gridDim.y) - pHeight - paddingY)
	{
		for (int j = -pHeight; j <= pHeight; j++)
		{
			for (int i = -pWidth; i <= pWidth; i++)
			{
				// Sample the weight for this location
				int ki = (i + pWidth);
				int kj = (j + pHeight);
				float w = convolutionKernelStore[(kj * kWidth) + ki + kOffset];


				sum += w * float(source[((y + j) * width) + (x + i)]);
			}
		}
	}

	// Promedio sum
	destination[(y * width) + x] = (unsigned char)sum;
}

__global__ void pythagoras(unsigned char *a, unsigned char *b, unsigned char *c)
{
	int idx = (blockIdx.x * blockDim.x) + threadIdx.x;

	float af = float(a[idx]);
	float bf = float(b[idx]);

	c[idx] = (unsigned char)sqrtf(af*af + bf * bf);
}

// crea imagen buffer
unsigned char* createImageBuffer(unsigned int bytes, unsigned char **devicePtr)
{
	unsigned char *ptr = NULL;
	cudaSetDeviceFlags(cudaDeviceMapHost);
	cudaHostAlloc(&ptr, bytes, cudaHostAllocMapped);
	cudaHostGetDevicePointer(devicePtr, ptr, 0);
	return ptr;
}


int main(int argc, char** argv) {
	// Abre la camaraweb
	cv::VideoCapture camera(0);
	cv::Mat          frame;
	if (!camera.isOpened())
		return -1;

	// capture windows
	cv::namedWindow("Source");
	cv::namedWindow("Greyscale");
	cv::namedWindow("Blurred");
	cv::namedWindow("Sobel");

	// Funciones para obtener el tiempo de ejecucion 
	cudaEvent_t start, stop;
	cudaEventCreate(&start);
	cudaEventCreate(&stop);

	// Crea kernel gaussian(sum = 159)
	const float gaussianKernel5x5[25] =
	{
		2.f / 159.f,  4.f / 159.f,  5.f / 159.f,  4.f / 159.f, 2.f / 159.f,
		4.f / 159.f,  9.f / 159.f, 12.f / 159.f,  9.f / 159.f, 4.f / 159.f,
		5.f / 159.f, 12.f / 159.f, 15.f / 159.f, 12.f / 159.f, 5.f / 159.f,
		4.f / 159.f,  9.f / 159.f, 12.f / 159.f,  9.f / 159.f, 4.f / 159.f,
		2.f / 159.f,  4.f / 159.f,  5.f / 159.f,  4.f / 159.f, 2.f / 159.f,
	};
	cudaMemcpyToSymbol(convolutionKernelStore, gaussianKernel5x5, sizeof(gaussianKernel5x5), 0);
	const unsigned int gaussianKernel5x5Offset = 0;

	// Sobel gradient kernels
	const float sobelGradientX[9] =
	{
		-1.f, 0.f, 1.f,
		-2.f, 0.f, 2.f,
		-1.f, 0.f, 1.f,
	};
	const float sobelGradientY[9] =
	{
		1.f, 2.f, 1.f,
		0.f, 0.f, 0.f,
		-1.f, -2.f, -1.f,
	};
	cudaMemcpyToSymbol(convolutionKernelStore, sobelGradientX, sizeof(sobelGradientX), sizeof(gaussianKernel5x5));
	cudaMemcpyToSymbol(convolutionKernelStore, sobelGradientY, sizeof(sobelGradientY), sizeof(gaussianKernel5x5) + sizeof(sobelGradientX));
	const unsigned int sobelGradientXOffset = sizeof(gaussianKernel5x5) / sizeof(float);
	const unsigned int sobelGradientYOffset = sizeof(sobelGradientX) / sizeof(float) + sobelGradientXOffset;

	// Crea CPU/GPU imagenes compartidos
	camera >> frame;
	unsigned char *sourceDataDevice, *blurredDataDevice, *edgesDataDevice;
	cv::Mat source(frame.size(), CV_8U, createImageBuffer(frame.size().width * frame.size().height, &sourceDataDevice));
	cv::Mat blurred(frame.size(), CV_8U, createImageBuffer(frame.size().width * frame.size().height, &blurredDataDevice));
	cv::Mat edges(frame.size(), CV_8U, createImageBuffer(frame.size().width * frame.size().height, &edgesDataDevice));

	// Crea 2 imagenes temporales (sobel gradients)
	unsigned char *deviceGradientX, *deviceGradientY;
	cudaMalloc(&deviceGradientX, frame.size().width * frame.size().height);
	cudaMalloc(&deviceGradientY, frame.size().width * frame.size().height);

	// Loop while captura imagenes
	while (1)
	{
		// Captura la imagen en escala de grises
		camera >> frame;
		cvtColor(frame, source, COLOR_RGB2GRAY);
		_sleep(1);
		// Graba el tiempo que demora el proceso
		cudaEventRecord(start);
		{
			// convolution kernel  parametros
			dim3 cblocks(frame.size().width / 16, frame.size().height / 16);
			dim3 cthreads(16, 16);

			// pythagoran kernel parametros
			dim3 pblocks(frame.size().width * frame.size().height / 256);
			dim3 pthreads(256, 1);

			//  gaussian blur (first kernel in store @ 0)
			convolve <<<cblocks, cthreads >> > (sourceDataDevice, frame.size().width, frame.size().height, 0, 0, gaussianKernel5x5Offset, 5, 5, blurredDataDevice);

			// sobel gradient convolutions (x&y padding is now 2 because there is a border of 2 around a 5x5 gaussian filtered image)
			convolve << <cblocks, cthreads >> > (blurredDataDevice, frame.size().width, frame.size().height, 2, 2, sobelGradientXOffset, 3, 3, deviceGradientX);
			convolve << <cblocks, cthreads >> > (blurredDataDevice, frame.size().width, frame.size().height, 2, 2, sobelGradientYOffset, 3, 3, deviceGradientY);
			pythagoras << <pblocks, pthreads >> > (deviceGradientX, deviceGradientY, edgesDataDevice);

			cudaThreadSynchronize();
		}
		cudaEventRecord(stop);

		// Muestra tiempo de ejecucion
		float ms = 0.0f;
		cudaEventSynchronize(stop);
		cudaEventElapsedTime(&ms, start, stop);
		std::cout << "Elapsed GPU time: " << ms << " milliseconds" << std::endl;

		// Muestra resultados
		imshow("Source", frame);
		imshow("Greyscale", source);
		imshow("Blurred", blurred);
		imshow("Sobel", edges);

		// Spin
		if (cv::waitKey(1) == 27) break;
	}

	// Exit
	cudaFreeHost(source.data);
	cudaFreeHost(blurred.data);
	cudaFreeHost(edges.data);
	cudaFree(deviceGradientX);
	cudaFree(deviceGradientY);

	return 0;
}

很多時(shí)候加上Cuda是有必要的,如果你要使用hough變換之類的時(shí)間復(fù)雜度比較高的代碼,Gpu編程會(huì)給你帶來多個(gè)數(shù)量級(jí)的加速。

到此這篇關(guān)于OpenCV圖像輪廓提取的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)OpenCV圖像輪廓提取內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C語言實(shí)現(xiàn)BMP圖像處理(直方圖均衡化)

    C語言實(shí)現(xiàn)BMP圖像處理(直方圖均衡化)

    這篇文章主要為大家詳細(xì)介紹了C語言實(shí)現(xiàn)BMP圖像直方圖均衡化處理,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-10-10
  • C語言 OpenCV實(shí)現(xiàn)柱面投影

    C語言 OpenCV實(shí)現(xiàn)柱面投影

    在做全景拼接的時(shí)候,為了保持圖片中的空間約束與視覺的一致性,需要進(jìn)行柱面投影,否則離中心圖像距離越遠(yuǎn)的圖像拼接后變形越大。本文將具體介紹一下這如何實(shí)現(xiàn),需要的可以參考一下
    2021-12-12
  • C++實(shí)現(xiàn)LeetCode(2.兩個(gè)數(shù)字相加)

    C++實(shí)現(xiàn)LeetCode(2.兩個(gè)數(shù)字相加)

    這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(兩個(gè)數(shù)字相加),本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • C++進(jìn)程的創(chuàng)建和進(jìn)程ID標(biāo)識(shí)詳細(xì)介紹

    C++進(jìn)程的創(chuàng)建和進(jìn)程ID標(biāo)識(shí)詳細(xì)介紹

    傳統(tǒng)的C++(C++98)中并沒有引入線程這個(gè)概念。linux和unix操作系統(tǒng)的設(shè)計(jì)采用的是多進(jìn)程,進(jìn)程間的通信十分方便,同時(shí)進(jìn)程之間互相有著獨(dú)立的空間,不會(huì)污染其他進(jìn)程的數(shù)據(jù),天然的隔離性給程序的穩(wěn)定性帶來了很大的保障
    2022-08-08
  • C語言宏定義容易認(rèn)不清的盲區(qū)梳理

    C語言宏定義容易認(rèn)不清的盲區(qū)梳理

    宏定義是C提供的三種預(yù)處理(宏定義、文件包含、條件編譯)的其中一種,其主要目的是為程序員在編程時(shí)提供一定的方便,并能在一定程度上提高程序的運(yùn)行效率
    2022-09-09
  • C語言自研定時(shí)器計(jì)劃任務(wù)語法詳解

    C語言自研定時(shí)器計(jì)劃任務(wù)語法詳解

    市面主流定時(shí)器計(jì)劃任務(wù)語法: cron ,但是使用起來非常難受,設(shè)計(jì)的比較非人性話語法,我想一般人都沒幾個(gè)記住的,所以本文將自研定時(shí)器計(jì)劃任務(wù)語法,需要的可以參考一下
    2022-09-09
  • C語言實(shí)現(xiàn)簡單的井字棋游戲

    C語言實(shí)現(xiàn)簡單的井字棋游戲

    這篇文章主要為大家詳細(xì)介紹了C語言實(shí)現(xiàn)簡單的井字棋游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-04-04
  • 聊聊C++中右值引用和移動(dòng)構(gòu)造函數(shù)的使用

    聊聊C++中右值引用和移動(dòng)構(gòu)造函數(shù)的使用

    這篇文章主要是來和大家一起聊聊C++中右值引用和移動(dòng)構(gòu)造函數(shù)的使用,文中通過示例進(jìn)行了詳細(xì)講解,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2022-07-07
  • socket編程之bind()函數(shù)使用示例詳解

    socket編程之bind()函數(shù)使用示例詳解

    這篇文章主要為大家介紹了socket編程之bind()函數(shù)使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-10-10
  • visual studio 2015下boost庫配置教程

    visual studio 2015下boost庫配置教程

    這篇文章主要為大家詳細(xì)介紹了visual studio 2015下boost庫的配置教程,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-04-04

最新評(píng)論

青田县| 余庆县| 桑日县| 精河县| 南宫市| 九龙城区| 永德县| 乌拉特前旗| 辽中县| 通山县| 锡林郭勒盟| 鞍山市| 合阳县| 金塔县| 申扎县| 永兴县| 密山市| 乌兰察布市| 永吉县| 陈巴尔虎旗| 星座| 西安市| 汶川县| 安义县| 长兴县| 桂东县| 钟山县| 齐河县| 前郭尔| 稻城县| 聂拉木县| 大名县| 交口县| 萝北县| 七台河市| 宁强县| 灵璧县| 错那县| 合川市| 泸定县| 潮州市|