05. 基于MFC实现最近邻图像缩放算法

本博文内容是博文基于MFC框架的图像缩放算法示例的一部分(返回目录)。

博文03. 用C++类和对象封装BMP显示的相关代码引入C++类的概念,将所用BMP处理相关的代码,包括读取BMP,分离R,G,B通道和绘制BMP等用一个CBmp类进行封装,实现了对BMP图像的读取,分离和绘制的功能。接下来我们介绍图像缩放算法的实现,并用BMP展示。

经典的图像缩放算法有最近邻算法、双线性算法和双三次算法三类,依次复杂度增加,缩放效果也依次改善。本博文系列为逐个介绍这三种算法。本文实现最简单的最近邻算法。

step 01: 为工程添加一个名为CScaleNearst的类

在名为MFC_SD_03的工程依次点击菜单项【项目】->【添加类】,会出现添加新的界面,填好类名CScaleNearst和文件名Scale_Nearst.hScale_Nearst.cpp点击【确定】按钮即可。

Scale_Nearst.h修改内容如下:

#pragma once
class CScaleNearst
{
public:
	CScaleNearst();
	~CScaleNearst();
public:
	int src_pix_pos_nearest(int in_width, int out_width, int dst_pos, int* src_pos);
	int line_scale_nearest(unsigned char* in_line, int in_width, 
						   unsigned char* out_line, int out_width);
	int col_scale_nearest(unsigned char* in_line, int in_height, 
						  unsigned char* out_line, int out_height, int out_width);
	int frame_scale_nearest(int in_width, int in_height, unsigned char* ch_img_in, 
							int dst_width, int dst_height,unsigned char* ch_img_out);		
};

Scale_Nearst.cpp修改内容如下:

#include "pch.h"
#include "Scale_nearst.h"

CScaleNearst::CScaleNearst() { }

CScaleNearst::~CScaleNearst() { }

// get source pixel position from destination postion
int CScaleNearst::src_pix_pos_nearest(int in_width, int out_width, int dst_pos, int* src_pos) {
	float scale = (float)(in_width) / (float)out_width;
	float srcpos_f;  //int srcpos_i;
	//get float position
	srcpos_f = dst_pos * scale;

	//change interger type
	*src_pos = (int)(srcpos_f + 0.5);  

	//Boundary Pixel Consideration
	for (int i = 0; i < 4; i++) { 
		if (*src_pos < 0) *src_pos = 0;
		if (*src_pos > (in_width - 1)) *src_pos = in_width - 1;
	}
	return 0;
}

//
int CScaleNearst::line_scale_nearest(unsigned char* in_line, int in_width, 
									 unsigned char* out_line, int out_width) {
	int src_pos;
	//float tmp = 0;
	for (int i = 0; i < out_width; i++)
	{ 
		src_pix_pos_nearest(in_width, out_width, i, &src_pos);
		out_line[i] = in_line[src_pos];
	}
	return 0;
}

int CScaleNearst::col_scale_nearest(unsigned char* in_line, int in_height, 
									unsigned char* out_line, int out_height, int out_width) {
	int src_pos;
	for (int i = 0; i < out_height; i++)
	{ 
		src_pix_pos_nearest(in_height, out_height, i, &src_pos);
		out_line[i * out_width] = in_line[src_pos * out_width];
	}
	return 0;
}

int CScaleNearst::frame_scale_nearest(
			int in_width, int in_height, 
			unsigned char* ch_img_in, 
			int dst_width, int dst_height,
			unsigned char* ch_img_out 			
) {

	unsigned char* tmp_frame = new unsigned char[1920*1080];

	for (int i = 0; i < in_height; i++) {
		line_scale_nearest(ch_img_in + i * in_width, in_width, tmp_frame + i * dst_width, dst_width);
	}
	for (int i = 0; i < dst_width; i++) {
		col_scale_nearest(tmp_frame + i, in_height, ch_img_out + i, dst_height, dst_width);
	}

	delete[] tmp_frame;
	return 0;
}

step 02: 为工程添加鼠标右键消息并进行图像缩放

前一篇博文我们已经实现了鼠标点击左键时绘制BMP原图,为了比对缩放图像和原图,我们再次添加鼠标右键的消息,在其消息响应函数内编写图像缩放和显示的代码。

有了CBmp和CScaleNearst两个类,我们就可以分步实现图像缩放了。即

  1. 读取图像CBmp::readBmp()
  2. 分离通道CBmp::separateRGB()
  3. 缩放每个通道CScaleNearst::frame_scale_nearest
  4. 合并绘制BMP图像CBmp::print_matrix
#include "Scale_nearst.h"
void CMFCSD03View::OnRButtonDown(UINT nFlags, CPoint point)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	CBmp bmp;
	CScaleNearst scaler;

	//要绘制的图像文件名
	char bmpName[] = "1.bmp";
	unsigned char* red_channel = new unsigned char[1920 * 1080];
	unsigned char* green_channel = new unsigned char[1920 * 1080];
	unsigned char* blue_channel = new unsigned char[1920 * 1080];

	unsigned char* img_data = new unsigned char[1920 * 1080 * 3];

	int bmpWidth = 0;
	int bmpHeight = 0;
	int biBitCount = 0;
	int lineByte = 0;

	//read bmp image
	bmp.readBmp(bmpName, img_data, &bmpWidth, &bmpHeight, &biBitCount, &lineByte);

	//separate to three channels
	bmp.separateRGB(img_data,
		red_channel, green_channel, blue_channel,
		bmpWidth, bmpHeight, lineByte);
	
	//scale the image
	int dstWidth = bmpWidth / 2;
	int dstHeight = bmpHeight / 2;

	scaler.frame_scale_nearest(
		bmpWidth, bmpHeight, red_channel,
		dstWidth, dstHeight, red_channel);

	scaler.frame_scale_nearest(
		bmpWidth, bmpHeight, green_channel,
		dstWidth, dstHeight, green_channel);

	scaler.frame_scale_nearest(
		bmpWidth, bmpHeight, blue_channel,
		dstWidth, dstHeight, blue_channel);


	//合并绘制三个通道的图像
	CClientDC dc(this);
	CDC* pDC = &dc;

	int offset_left = point.x;
	int offset_top = point.y;

	bmp.print_matrix(pDC,
		red_channel, green_channel, blue_channel,
		dstWidth, dstHeight,
		offset_left, offset_top);

	//important to clear the memory used
	delete[] red_channel;
	delete[] green_channel;
	delete[] blue_channel;
	delete[] img_data;

	CView::OnRButtonDown(nFlags, point);
}

编译执行MFC工程,会发现每次点击鼠标左键都会以点击的位置为左上角绘制指定的BMP图像原图,而点击右键时会绘制缩放后的BMP图像。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值