Advertisement

Splitting image into tiles

Started by August 21, 2024 06:45 PM
2 comments, last by taby 4 months ago

I am having some trouble with an OpenGL code. The input is correct, but the output is not.

The code is as follows. When I change num_tiles_per_dimension to 1 then everything works well, which goes to show that the code is pretty much working. The full code is at: https://github.com/sjhalayka/light_blocking_asymmetric

		int num_tiles_per_dimension = 2;

		std::vector<cv::Mat> array_of_input_mats = splitImage(input_mat, num_tiles_per_dimension, num_tiles_per_dimension);
		std::vector<cv::Mat> array_of_output_mats;

		for (size_t i = 0; i < array_of_input_mats.size(); i++)
		{
			string s = "_input_" + to_string(i) + ".png";
			imwrite(s.c_str(), array_of_input_mats[i]);

			vector<float> output_pixels(4 * array_of_input_mats[i].rows * array_of_input_mats[i].cols);

			gpu_compute(
				compute_shader_program,
				&output_pixels[0],
				array_of_input_mats[i],
				input_light_mat_with_dynamic_lights,
				input_light_blocking_mat);

			Mat uc_output_small(array_of_input_mats[i].rows, array_of_input_mats[i].cols, CV_8UC4);

			for (size_t x = 0; x < (4 * uc_output_small.rows * uc_output_small.cols); x += 4)
			{
				uc_output_small.data[x + 0] = static_cast<unsigned char>(output_pixels[x + 0] * 255.0);
				uc_output_small.data[x + 1] = static_cast<unsigned char>(output_pixels[x + 1] * 255.0);
				uc_output_small.data[x + 2] = static_cast<unsigned char>(output_pixels[x + 2] * 255.0);
				uc_output_small.data[x + 3] = 255;
			}

			array_of_output_mats.push_back(uc_output_small);

			// These images show that something's not working right where num_tiles_per_dimension is >= 2
			// there are duplicate output images
			s = "_output_" + to_string(i) + ".png";
			imwrite(s.c_str(), array_of_output_mats[i]);
		}


		cv::Mat uc_output = imageCollage(array_of_output_mats, num_tiles_per_dimension, num_tiles_per_dimension);
		
		

The input images are:

The output images are:

As you can see, the output is not right, even though the input is right – the 1st and 2nd output images are repeats. This should not be.

Any ideas?

I used the tile splitImage and imageCollage functions in another part of the program (the randomization of the hue and brightness), and it works just fine too.

In any case, here is the output where num_tiles_per_dimension = 2:

And here's where num_tiles_per_dimension = 1:

I changed the code to return a Mat instead of using a pointer, and now it gives me random noise.

I'm somehow not returning the Mat correctly.


		int num_tiles_per_dimension = 1;

		std::vector<cv::Mat> array_of_input_mats = splitImage(input_mat, num_tiles_per_dimension, num_tiles_per_dimension);
		std::vector<cv::Mat> array_of_output_mats;

		for (size_t i = 0; i < array_of_input_mats.size(); i++)
		{
			string s = "_input_" + to_string(i) + ".png";
			imwrite(s.c_str(), array_of_input_mats[i]);

			Mat compute_result = gpu_compute(
				compute_shader_program,
				array_of_input_mats[i],
				input_light_mat_with_dynamic_lights,
				input_light_blocking_mat);

			Mat uc_output_small(array_of_input_mats[i].rows, array_of_input_mats[i].cols, CV_8UC4);

			for (size_t x = 0; x < (4 * uc_output_small.rows * uc_output_small.cols); x += 4)
			{
				uc_output_small.data[x + 0] = static_cast<unsigned char>(compute_result.data[x + 0] * 255.0);
				uc_output_small.data[x + 1] = static_cast<unsigned char>(compute_result.data[x + 1] * 255.0);
				uc_output_small.data[x + 2] = static_cast<unsigned char>(compute_result.data[x + 2] * 255.0);
				uc_output_small.data[x + 3] = 255;
			}

			array_of_output_mats.push_back(uc_output_small);

			// These images show that something's not working right where num_tiles_per_dimension is >= 2
			// there are duplicate output images
			s = "_output_" + to_string(i) + ".png";
			imwrite(s.c_str(), array_of_output_mats[i]);
		}


		cv::Mat uc_output = imageCollage(array_of_output_mats, num_tiles_per_dimension, num_tiles_per_dimension);
		uc_output = anti_alias_mat(uc_output);
		

The rest of the relevant code changes are:


Mat compute(
	GLuint& compute_shader_program,
	const Mat& input_pixels,
	const Mat& input_light_pixels,
	const Mat& input_light_blocking_pixels)
{
	Mat output_mat(input_pixels.rows, input_pixels.cols, CV_32FC4, Scalar(1, 1, 1, 1));

	const GLint tex_w_small = input_pixels.cols;
	const GLint tex_h_small = input_pixels.rows;

	const GLint tex_w_full_size = input_light_pixels.cols;
	const GLint tex_h_full_size = input_light_pixels.rows;

	glEnable(GL_TEXTURE_2D);

	GLuint tex_input = 0;
	GLuint tex_light_input = 0;
	GLuint tex_light_blocking_input = 0;

	glGenTextures(1, &tex_input);
	glActiveTexture(GL_TEXTURE1);
	glBindTexture(GL_TEXTURE_2D, tex_input);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

	glGenTextures(1, &tex_light_input);
	glActiveTexture(GL_TEXTURE2);
	glBindTexture(GL_TEXTURE_2D, tex_light_input);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

	glGenTextures(1, &tex_light_blocking_input);
	glActiveTexture(GL_TEXTURE3);
	glBindTexture(GL_TEXTURE_2D, tex_light_blocking_input);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);


	GLuint tex_output = 0;
	glGenTextures(1, &tex_output);

	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D, tex_output);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, tex_w_small, tex_h_small, 0, GL_RGBA, GL_FLOAT, NULL);
	glBindImageTexture(0, tex_output, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);

	glActiveTexture(GL_TEXTURE1);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, tex_w_small, tex_h_small, 0, GL_RGBA, GL_FLOAT, input_pixels.data);
	glBindImageTexture(1, tex_input, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA32F);



	glActiveTexture(GL_TEXTURE2);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, tex_w_full_size, tex_h_full_size, 0, GL_RGBA, GL_FLOAT, input_light_pixels.data);
	glBindImageTexture(2, tex_light_input, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA32F);

	glActiveTexture(GL_TEXTURE3);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, tex_w_full_size, tex_h_full_size, 0, GL_RGBA, GL_FLOAT, input_light_blocking_pixels.data);
	glBindImageTexture(3, tex_light_blocking_input, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA32F);




	// Use the compute shader
	glUseProgram(compute_shader_program);

	glUniform1i(glGetUniformLocation(compute_shader_program, "input_image"), 1);
	glUniform1i(glGetUniformLocation(compute_shader_program, "input_light_image"), 2);
	glUniform1i(glGetUniformLocation(compute_shader_program, "input_light_blocking_image"), 3);
	glUniform2i(glGetUniformLocation(compute_shader_program, "u_size"), tex_w_full_size, tex_h_full_size);

	// Run compute shader
	glDispatchCompute((GLuint)tex_w_small, (GLuint)tex_h_small, 1);

	// Wait for compute shader to finish
	glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);

	// Copy output pixel array to CPU as texture 0
	glActiveTexture(GL_TEXTURE0);
	glBindImageTexture(0, tex_output, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);
	glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_FLOAT, output_mat.data);

	glDeleteTextures(1, &tex_output);
	glDeleteTextures(1, &tex_input);
	glDeleteTextures(1, &tex_light_input);
	glDeleteTextures(1, &tex_light_blocking_input);

	return output_mat;
}




Mat gpu_compute(
	GLuint& compute_shader_program,
	const Mat input_mat,
	const Mat& input_light_mat_with_dynamic_lights,
	const Mat& input_light_blocking_mat)
{
	const GLint tex_w_small = input_mat.cols;
	const GLint tex_h_small = input_mat.rows;

	const GLint tex_w_full_size = input_light_mat_with_dynamic_lights.cols;
	const GLint tex_h_full_size = input_light_mat_with_dynamic_lights.rows;


	Mat input_mat_float(tex_w_small, tex_h_small, CV_32FC4);

	for (int i = 0; i < tex_w_small; i++)
	{
		for (int j = 0; j < tex_h_small; j++)
		{
			Vec4b pixelValue = input_mat.at<Vec4b>(j, i);
			Vec4f p;

			p[0] = pixelValue[0] / 255.0f;
			p[1] = pixelValue[1] / 255.0f;
			p[2] = pixelValue[2] / 255.0f;
			p[3] = pixelValue[3] / 255.0f;

			input_mat_float.at<Vec4f>(j, i) = p;
		}
	}


	Mat input_light_mat_float(tex_w_full_size, tex_h_full_size, CV_32FC4);

	for (int i = 0; i < tex_w_full_size; i++)
	{
		for (int j = 0; j < tex_h_full_size; j++)
		{
			Vec4b pixelValue = input_light_mat_with_dynamic_lights.at<Vec4b>(j, i);
			Vec4f p;// = pixelValue / 255.0f;

			p[0] = pixelValue[0] / 255.0f;
			p[1] = pixelValue[1] / 255.0f;
			p[2] = pixelValue[2] / 255.0f;
			p[3] = pixelValue[3] / 255.0f;

			input_light_mat_float.at<Vec4f>(j, i) = p;
		}
	}


	Mat input_light_blocking_mat_float(tex_w_full_size, tex_h_full_size, CV_32FC4);

	for (int i = 0; i < tex_w_full_size; i++)
	{
		for (int j = 0; j < tex_h_full_size; j++)
		{
			Vec4b pixelValue = input_light_blocking_mat.at<Vec4b>(j, i);
			Vec4f p;// = pixelValue / 255.0f;

			p[0] = pixelValue[0] / 255.0f;
			p[1] = pixelValue[1] / 255.0f;
			p[2] = pixelValue[2] / 255.0f;
			p[3] = pixelValue[3] / 255.0f;

			input_light_blocking_mat_float.at<Vec4f>(j, i) = p;
		}
	}

	Mat c = compute(
		compute_shader_program,
		input_mat_float,
		input_light_mat_float,
		input_light_blocking_mat_float);

	return c;
}
Advertisement

I boiled it down to only a couple of lines' difference.

Here is the float* version, which works:

		int num_tiles_per_dimension = 1;

		std::vector<cv::Mat> array_of_input_mats = splitImage(input_mat, num_tiles_per_dimension, num_tiles_per_dimension);
		std::vector<cv::Mat> array_of_output_mats;

		for (size_t i = 0; i < array_of_input_mats.size(); i++)
		{
			string s = "_input_" + to_string(i) + ".png";
			imwrite(s.c_str(), array_of_input_mats[i]);

			vector<float> output_pixels(4 * array_of_input_mats[i].rows * array_of_input_mats[i].cols);
		
			//Mat output_pixels(array_of_input_mats[i].rows, array_of_input_mats[i].cols, CV_32FC4);


			gpu_compute(
				compute_shader_program,
				reinterpret_cast<unsigned char*>(output_pixels.data()),
				array_of_input_mats[i],
				input_light_mat_with_dynamic_lights,
				input_light_blocking_mat);

			Mat uc_output_small(array_of_input_mats[i].rows, array_of_input_mats[i].cols, CV_8UC4);

			for (size_t x = 0; x < (4 * uc_output_small.rows * uc_output_small.cols); x += 4)
			{
				uc_output_small.data[x + 0] = static_cast<unsigned char>(output_pixels[x + 0] * 255.0);
				uc_output_small.data[x + 1] = static_cast<unsigned char>(output_pixels[x + 1] * 255.0);
				uc_output_small.data[x + 2] = static_cast<unsigned char>(output_pixels[x + 2] * 255.0);
				uc_output_small.data[x + 3] = 255;
			}

			array_of_output_mats.push_back(uc_output_small);

			// These images show that something's not working right where num_tiles_per_dimension is >= 2
			// there are duplicate output images
			s = "_output_" + to_string(i) + ".png";
			imwrite(s.c_str(), array_of_output_mats[i]);
		}
		

Here is the Mat version, which does not work:

		int num_tiles_per_dimension = 1;

		std::vector<cv::Mat> array_of_input_mats = splitImage(input_mat, num_tiles_per_dimension, num_tiles_per_dimension);
		std::vector<cv::Mat> array_of_output_mats;

		for (size_t i = 0; i < array_of_input_mats.size(); i++)
		{
			string s = "_input_" + to_string(i) + ".png";
			imwrite(s.c_str(), array_of_input_mats[i]);

			//vector<float> output_pixels(4 * array_of_input_mats[i].rows * array_of_input_mats[i].cols);
		
			Mat output_pixels(array_of_input_mats[i].rows, array_of_input_mats[i].cols, CV_32FC4);


			gpu_compute(
				compute_shader_program,
				reinterpret_cast<unsigned char*>(output_pixels.data),
				array_of_input_mats[i],
				input_light_mat_with_dynamic_lights,
				input_light_blocking_mat);

			Mat uc_output_small(array_of_input_mats[i].rows, array_of_input_mats[i].cols, CV_8UC4);

			for (size_t x = 0; x < (4 * uc_output_small.rows * uc_output_small.cols); x += 4)
			{
				uc_output_small.data[x + 0] = static_cast<unsigned char>(output_pixels.data[x + 0] * 255.0);
				uc_output_small.data[x + 1] = static_cast<unsigned char>(output_pixels.data[x + 1] * 255.0);
				uc_output_small.data[x + 2] = static_cast<unsigned char>(output_pixels.data[x + 2] * 255.0);
				uc_output_small.data[x + 3] = 255;
			}

			array_of_output_mats.push_back(uc_output_small);

			// These images show that something's not working right where num_tiles_per_dimension is >= 2
			// there are duplicate output images
			s = "_output_" + to_string(i) + ".png";
			imwrite(s.c_str(), array_of_output_mats[i]);
		}
		

Why???

This topic is closed to new replies.

Advertisement