[Tutorial introdutório 6 do OpenCV] Criar Trackbar e ajustar o contraste da imagem e o valor de brilho



Esta série de artigos é produzida por @ 浅 墨 _ 毛星云, favor indicar a fonte para a reimpressão.
Link do artigo: http://blog.csdn.net/poem_qianmo/article/details/21176257
A versão OpenCV usada ao escrever a postagem atual do blog: 4.20

Neste artigo, aprendemos como criar e usar track bars com a função createTrackbar no OpenCV, bem como o ajuste dinâmico dos valores de contraste e brilho da imagem.

O artigo primeiro explicou em detalhes a função createTrackbar na nova versão do OpenCV2.0 e deu um exemplo de um comentário detalhado.

Em seguida, explique os detalhes do contraste da imagem e ajuste de brilho, e finalmente lançou um código-fonte do programa que usa a função createTrackbar para criar uma barra de controle para auxiliar no contraste da imagem e ajuste de brilho.

Ainda coloque uma captura de tela da operação primeiro:
Insira a descrição da imagem aqui
OK, vamos começar oficialmente nossa explicação.

1. A criação e uso de Trackbar em OpenCV

<1> Crie uma barra de trilha - uma explicação detalhada da função createTrackbar

A função createTrackbar será usada freqüentemente no futuro.Ela cria uma barra de controle que pode ajustar o valor e anexa a barra de controle à janela especificada, o que é muito conveniente de usar. Em primeiro lugar, todos devem se lembrar que geralmente é usado em conjunto com uma função de retorno de chamada. Primeiro, olhe para seu protótipo de função:

C++: int createTrackbar(conststring& trackbarname, conststring& winname,
 int* value, int count, TrackbarCallback onChange=0,void* userdata=0);

O primeiro parâmetro , trackbarname de const string & type, representa o nome da barra de trilha, que é usado para representar a barra de trilha que criamos.
O segundo parâmetro , winname de const string & type, preenche o nome da janela, que indica a qual janela a barra de controle será anexada, o que corresponde a um determinado nome de janela preenchido quando namedWindow () cria a janela.
O terceiro parâmetro , valor do tipo int *, um ponteiro para um inteiro, indicando a posição do controle deslizante. E quando ele é criado, a posição inicial do controle deslizante é o valor atual da variável.
O quarto parâmetro , contagem do tipo int, representa o valor da posição máxima que o controle deslizante pode alcançar. PS: O valor da menor posição do controle deslizante é sempre 0.
O quinto parâmetro , onChange do tipo TrackbarCallback, primeiro observe que ele tem um valor padrão de 0. Este é um ponteiro para uma função de retorno de chamada. Essa função fará um retorno de chamada toda vez que a posição do controle deslizante mudar. E o protótipo desta função deve ser void XXXX (int, void *); o primeiro parâmetro é a posição da barra de controle e o segundo parâmetro são os dados do usuário (veja o sexto parâmetro abaixo). Se o retorno de chamada for um ponteiro NULL, significa que não há chamada de função de retorno de chamada e apenas o terceiro valor do parâmetro foi alterado.
O sexto parâmetro , userdata do tipo void *, também tem um valor padrão de 0. Este parâmetro são os dados passados ​​pelo usuário para a função de retorno de chamada para processar os eventos da barra de controle. Se o terceiro argumento de valor de parâmetro usado for uma variável global, você pode ignorar o parâmetro userdata.

Esta função createTrackbar cria uma barra de trilha (Trackbar ou ferramenta de controle de faixa deslizante) com um nome e intervalo específicos para nós, e especifica uma variável que é sincronizada com a posição da barra de trilha. E você precisa especificar a função de retorno de chamada onChange (o quinto parâmetro), que é chamada quando a posição da barra de controle muda. E sabemos que a barra de trilha criada é exibida na janela representada pelo winname especificado (o segundo parâmetro).

Depois de ler a explicação da função, vamos primeiro dar um pequeno exemplo de uso da função:

 //创建轨迹条
       createTrackbar("对比度:", "【效果图窗口】",&g_nContrastValue,
300,ContrastAndBright );// g_nContrastValue为全局的整型变量,ContrastAndBright为回调函数的函数名(即指向函数地址的指针)

Vamos dar um exemplo completo de uso. Este é o programa de amostra oficial do OpenCV, um programa que demonstra o uso de barras de controle para controlar a detecção e o preenchimento do contorno. Qianmo disponibiliza sua modificação, simplificação de código e comentários detalhados para que todos possam digerir e estudar. Haverá uma explicação mais detalhada sobre a detecção de contorno na postagem atualizada do blog posteriormente.

//-----------------------------------【头文件包含部分】---------------------------------------
//	描述:包含程序所依赖的头文件
//---------------------------------------------------------------------------------------------- 
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <iostream>

//-----------------------------------【命名空间声明部分】---------------------------------------
//	描述:包含程序所使用的命名空间
//-----------------------------------------------------------------------------------------------   
using namespace cv;
using namespace std;

//-----------------------------------【全局函数声明部分】--------------------------------------
//	描述:全局函数声明
//-----------------------------------------------------------------------------------------------
Mat img;
int threshval = 160;			//轨迹条滑块对应的值,给初值160

//-----------------------------【on_trackbar( )函数】------------------------------------
//	描述:轨迹条的回调函数
//-----------------------------------------------------------------------------------------------
static void on_trackbar(int, void*)
{
	Mat bw = threshval < 128 ? (img < threshval) : (img > threshval);

	//定义点和向量
	vector<vector<Point> > contours;
	vector<Vec4i> hierarchy;

	//查找轮廓
	findContours(bw, contours, hierarchy, RETR_CCOMP, CHAIN_APPROX_SIMPLE);
	//初始化dst
	Mat dst = Mat::zeros(img.size(), CV_8UC3);
	//开始处理
	if (!contours.empty() && !hierarchy.empty())
	{
		//遍历所有顶层轮廓,随机生成颜色值绘制给各连接组成部分
		int idx = 0;
		for (; idx >= 0; idx = hierarchy[idx][0])
		{
			Scalar color((rand() & 255), (rand() & 255), (rand() & 255));
			//绘制填充轮廓
			drawContours(dst, contours, idx, color, FILLED, 8, hierarchy);
		}
	}
	//显示窗口
	imshow("Connected Components", dst);
}


//-----------------------------------【main( )函数】--------------------------------------------
//	描述:控制台应用程序的入口函数,我们的程序从这里开始
//-----------------------------------------------------------------------------------------------
int main()
{
	system("color 5F");
	//载入图片
	img = imread("1.jpg", 0);
	if (!img.data) { printf("Oh,no,读取img图片文件错误~! \n"); return -1; }

	//显示原图
	namedWindow("Image", 1);
	imshow("Image", img);

	//创建处理窗口
	namedWindow("Connected Components", 1);
	//创建轨迹条
	createTrackbar("Threshold", "Connected Components", &threshval, 255, on_trackbar);
	on_trackbar(threshval, 0);//轨迹条回调函数

	waitKey(0);
	return 0;
}

Imagem original:
Insira a descrição da imagem aqui
Imagem de efeito de corrida:
Insira a descrição da imagem aqui

Arraste a barra de rolagem para alterar o valor do limiar (limite) para obter imagens com efeitos diferentes:

Insira a descrição da imagem aqui
Além disso, você pode encontrar o código oficial original no caminho OpenCV opencv_source_code / samples / cpp / connected_components.cpp.

A propósito, vamos falar sobre uma função usada com createTrackbar, a função getTrackbarPos usada para obter a posição da barra de controle atual.

<2> Obtenha a posição da função track bar-getTrackbarPos atual

<2> Obtenha a posição da função track bar-getTrackbarPos atual

Esta função é usada para obter a posição da barra de trilha atual e retorná-la.

O primeiro parâmetro , trackbarname do tipo const string &, representa o nome da trackbar.
O segundo parâmetro , winname do tipo const string &, representa o nome da janela pai da barra de controle.

Provavelmente é isso para esta parte. Vamos para a próxima parte sem parar :)

2. Base teórica para ajuste de brilho e contraste

Primeiro, damos o conceito de operadores. O operador geral de processamento de imagem é uma função que aceita uma ou mais imagens de entrada e produz uma imagem de saída. A fórmula a seguir fornece a forma geral do operador:

Insira a descrição da imagem aqui
A operação de ajuste do brilho e contraste da imagem que estamos explicando hoje é, na verdade, um tipo relativamente simples de operadores de ponto de transformação de processamento de imagem. A operação de ponto tem uma característica, apenas com base no valor do pixel de entrada (às vezes pode adicionar algumas informações ou parâmetros globais), para calcular o valor do pixel de saída correspondente. Esses operadores incluem ajustes de brilho e contraste, bem como correções e transformações de cores.

As duas operações de ponto (ou operadores de ponto) mais comumente usadas, obviamente, são multiplicar por uma constante (correspondendo ao ajuste do contraste) e adicionar uma constante (correspondendo ao ajuste do valor de brilho). A fórmula é assim:

Insira a descrição da imagem aqui
Vendo essa fórmula, nossa estratégia de ajuste de brilho e contraste da imagem está pronta para sair.

entre eles:

** Parâmetro f (x) ** representa o pixel da imagem de origem.
O parâmetro g (x) representa os pixels da imagem de saída.
O parâmetro a (precisa satisfazer a> 0) é chamado de ganho e é freqüentemente usado para controlar o contraste da imagem.
O parâmetro b é geralmente chamado de viés e é freqüentemente usado para controlar o brilho da imagem.

E um passo mais perto, reescrevemos esta fórmula assim:
Insira a descrição da imagem aqui
onde i e j indicam que o pixel está localizado na i-ésima linha e j-ésima coluna.

Então, esta fórmula pode ser usada como uma fórmula teórica para controlar o brilho e o contraste da imagem no OpenCV.

3. Sobre o acesso a pixels em imagens

Existem muitas maneiras de acessar os pixels na imagem, e a tinta clara usará um tópico para explicar no futuro. No momento, podemos primeiro entender o seguinte.

Para realizar esta operação, precisamos acessar cada pixel da imagem. Como a operação é realizada em imagens GBR, cada pixel possui três valores (G, B, R), portanto, devemos acessá-los separadamente (o modo de armazenamento de imagens em PS: OpenCV é GBR). O seguinte é um snippet de código para acessar o pixel. Três loops for resolvem o problema:

//三个for循环,执行运算 new_image(i,j) =a*image(i,j) + b
       for(int y = 0; y < image.rows; y++ )
       {
              for(int x = 0; x < image.cols; x++ )
              {
                     for(int c = 0; c < 3; c++ )
                     {
                            new_image.at<Vec3b>(y,x)[c]= saturate_cast<uchar>( (g_nContrastValue*0.01)*(image.at<Vec3b>(y,x)[c] ) + g_nBrightValue );
                     }
              }
       }

Vamos explicar em três aspectos:

Para acessar cada pixel da imagem, usamos esta sintaxe: image.at (y, x) [c]

Entre eles, y é a linha onde o pixel está localizado, x é a coluna onde o pixel está localizado e c é um de R, G e B (correspondendo a 0, 1, 2).

Como o resultado do nosso cálculo pode exceder a faixa de valores de pixel (estouro) ou pode ser um número não inteiro (se for um número de ponto flutuante), precisamos usar saturate_cast para converter o resultado para garantir que seja um valor válido.

Aqui, a é o contraste. Geralmente, o valor é um valor de ponto flutuante de 0,0 a 3,0 para o efeito da observação, mas nossa barra de controle geralmente assume um valor inteiro, então aqui podemos definir o parâmetro nContrastValue que representa o valor de contraste. é um número inteiro entre 0 e 300. Multiplique 0,01 na fórmula final, para que você possa completar a alteração de 300 valores diferentes na barra de controle. Portanto, na fórmula, veremos g_nContrastValue * 0,01 em saturate_cast ((g_nContrastValue 0,01) (image.at (y, x) [c]) + g_nBrightValue).

Quatro, contraste de imagem, programa de amostra de ajuste de valor de brilho

Ainda é uma postagem de blog com anotações detalhadas que dá suporte ao programa de amostra que cada artigo será atribuído a você. Os pontos de conhecimento apresentados neste artigo são usados ​​como uma portadora para mostrar o código.

Este programa de amostra usa duas barras de controle para controlar os valores de contraste e brilho, respectivamente, que tem um certo grau de capacidade de reprodução. Sem muita bobagem, vamos ao código:

// 操作系统: Windows 10 64bit
// 开发语言: C++
// IDE 版 本:Visual Studio 2019
// OpenCV版本:4.20
//-----------------------------------【头文件包含部分】---------------------------------------
//	描述:包含程序所依赖的头文件
//---------------------------------------------------------------------------------------------- 
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>

//-----------------------------------【命名空间声明部分】---------------------------------------
//	描述:包含程序所使用的命名空间
//-----------------------------------------------------------------------------------------------   
using namespace std;
using namespace cv;


//-----------------------------------【全局函数声明部分】--------------------------------------
//	描述:全局函数声明
//-----------------------------------------------------------------------------------------------
static void ContrastAndBright(int, void*);
void   ShowHelpText();

//-----------------------------------【全局变量声明部分】--------------------------------------
//	描述:全局变量声明
//-----------------------------------------------------------------------------------------------
int g_nContrastValue; //对比度值
int g_nBrightValue;  //亮度值
Mat g_srcImage, g_dstImage;
//-----------------------------------【main( )函数】--------------------------------------------
//	描述:控制台应用程序的入口函数,我们的程序从这里开始
//-----------------------------------------------------------------------------------------------
int main()
{
	//改变控制台前景色和背景色
	system("color 2F");

	// 读入用户提供的图像
	g_srcImage = imread("1.jpg");
	if (!g_srcImage.data) { printf("读取g_srcImage图片错误~! \n"); return false; }
	g_dstImage = Mat::zeros(g_srcImage.size(), g_srcImage.type());

	//设定对比度和亮度的初值
	g_nContrastValue = 80;
	g_nBrightValue = 80;

	//创建窗口
	namedWindow("【效果图窗口】", 1);

	//创建轨迹条
	createTrackbar("对比度:", "【效果图窗口】", &g_nContrastValue, 300, ContrastAndBright);
	createTrackbar("亮   度:", "【效果图窗口】", &g_nBrightValue, 200, ContrastAndBright);

	//调用回调函数
	ContrastAndBright(g_nContrastValue, 0);
	ContrastAndBright(g_nBrightValue, 0);

	//输出一些帮助信息
	cout << endl << "\t运行成功,请调整滚动条观察图像效果\n\n"
		<< "\t按下“q”键时,程序退出\n";

	//按下“q”键时,程序退出
	while (char(waitKey(1)) != 'q') {}
	return 0;
}


//-----------------------------【ContrastAndBright( )函数】------------------------------------
//	描述:改变图像对比度和亮度值的回调函数
//-----------------------------------------------------------------------------------------------
static void ContrastAndBright(int, void*)
{

	// 创建窗口
	namedWindow("【原始图窗口】", 1);

	// 三个for循环,执行运算 g_dstImage(i,j) = a*g_srcImage(i,j) + b
	for (int y = 0; y < g_srcImage.rows; y++)
	{
		for (int x = 0; x < g_srcImage.cols; x++)
		{
			for (int c = 0; c < 3; c++)
			{
				g_dstImage.at<Vec3b>(y, x)[c] = saturate_cast<uchar>((g_nContrastValue * 0.01) * (g_srcImage.at<Vec3b>(y, x)[c]) + g_nBrightValue);
			}
		}
	}

	// 显示图像
	imshow("【原始图窗口】", g_srcImage);
	imshow("【效果图窗口】", g_dstImage);
}

Finalmente, dê uma olhada nas imagens da operação.Quando você executa este programa, você obterá duas janelas de exibição de imagens. A primeira é a janela da imagem original e a segunda é a janela da imagem do efeito. Duas barras de controle podem ser ajustadas na janela da imagem de efeito para alterar o contraste e o brilho da imagem atual.

Imagem original:
Insira a descrição da imagem aqui
Insira a descrição da imagem aqui

Acho que você gosta

Origin blog.csdn.net/m0_51233386/article/details/114667113
Recomendado
Clasificación