关于TIF图片处理问题
下面的代码可以将bmp24位图片进行膨胀处理,但仅限于bmp格式和24位色彩模式,请问怎样修改它才能让它直接处理TIF格式的1位色彩模式,或者8位色彩模式的二值图,因为图片比较大的时侯 photoshop没办法保存为bmp格式,只能保存为TIF格式#include "pch.h"
#include "framework.h"
#include "TTS.h"
#include "TTSDlg.h"
#include "afxdialogex.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
#pragma warning(disable:4996);//出现fopen错误使用此代码
void CTTSDlg::OnBnClickedButton1()
{
int m_nWidth; //图像实际宽度
int m_nHeight; //图像实际高度
int m_nDrawWidth; //图像显示宽度
int m_nDrawHeight; //图像显示高度
DWORD m_nImage; //图像数据的字节数 只含位图
DWORD m_nSize; //图像文件大小
int m_nLineByte; //图像一行所占字节数
int m_nBitCount; //图像每个像素所占位数
int m_nPalette; //位图实际使用的颜色表中的颜色数
CBitmap m_bitmaplin; //创建临时位图对象进行处理
CString BmpNameLin; //保存图像副本文件
BYTE* m_pImage; //读入图片数据后的指针
BITMAPFILEHEADER bfh; //全局变量文件头
BITMAPINFOHEADER bih; //全局变量信息头
FILE* fp = fopen("test1.bmp", "rb");
if (fp == 0)
{
AfxMessageBox(_T("无法打开文件!"), MB_OK, 0);
return;
}
//读取文件头 解决BMP格式倒置的方法
fread(&bfh.bfType, sizeof(WORD), 1, fp);
fread(&bfh.bfSize, sizeof(DWORD), 1, fp);
fread(&bfh.bfReserved1, sizeof(WORD), 1, fp);
fread(&bfh.bfReserved2, sizeof(WORD), 1, fp);
fread(&bfh.bfOffBits, sizeof(DWORD), 1, fp);
//图像文件的总字节数
m_nSize = bfh.bfSize;
//判断是否是bmp格式图片
if (bfh.bfType != 0x4d42) //'BM'
{
AfxMessageBox(_T("不是BMP格式图片!"), MB_OK, 0);
return;
}
//读取信息头
fread(&bih.biSize, sizeof(DWORD), 1, fp);
fread(&bih.biWidth, sizeof(LONG), 1, fp);
fread(&bih.biHeight, sizeof(LONG), 1, fp);
fread(&bih.biPlanes, sizeof(WORD), 1, fp);
fread(&bih.biBitCount, sizeof(WORD), 1, fp);
fread(&bih.biCompression, sizeof(DWORD), 1, fp);
fread(&bih.biSizeImage, sizeof(DWORD), 1, fp);
fread(&bih.biXPelsPerMeter, sizeof(LONG), 1, fp);
fread(&bih.biYPelsPerMeter, sizeof(LONG), 1, fp);
fread(&bih.biClrUsed, sizeof(DWORD), 1, fp);
fread(&bih.biClrImportant, sizeof(DWORD), 1, fp);
if (bih.biSize != sizeof(bih))
{
AfxMessageBox(_T("本结构所占用字节数出现错误"));
return;
}
//位图压缩类型,必须是 0(不压缩) 1(BI_RLE8压缩类型)或2(BI_RLE压缩类型)之一
if (bih.biCompression == BI_RLE8 || bih.biCompression == BI_RLE4)
{
AfxMessageBox(_T("位图被压缩!"));
return;
}
//获取图像高宽和每个像素所占位数
m_nHeight = bih.biHeight;
m_nWidth = bih.biWidth;
m_nDrawHeight = bih.biHeight;
m_nDrawWidth = bih.biWidth;
m_nBitCount = bih.biBitCount; //每个像素所占位数
//计算图像每行像素所占的字节数(必须是32的倍数)
m_nLineByte = (m_nWidth * m_nBitCount + 31) / 32 * 4;
//图片大小 调用系统自带的文件头 BITMAPFILEHEADER bfh; BITMAPINFOHEADER bih;
//否则用 BITMAPFILEHEADER_ bfh; BITMAPINFOHEADER_ bih;要 m_nImage = m_nLineByte * m_nHeight - 2;
m_nImage = m_nLineByte * m_nHeight;
//位图实际使用的颜色表中的颜色数 biClrUsed
m_nPalette = 0; //初始化
if (bih.biClrUsed)
m_nPalette = bih.biClrUsed;
//申请位图空间 大小为位图大小 m_nImage
//malloc只能申请4字节的空间 (未知)
m_pImage = (BYTE*)malloc(m_nImage);
int num;//记录每一行需要填充的字节
if (m_nWidth * 3 % 4 != 0)
{
num = 4 - m_nWidth * 3 % 4;
}
else
{
num = 0;
}
//打开临时的图片
FILE* fpw = fopen("output.bmp", "wb+");
fwrite(&bfh, sizeof(BITMAPFILEHEADER), 1, fpw);
fwrite(&bih, sizeof(BITMAPINFOHEADER), 1, fpw);
fread(m_pImage, m_nImage, 1, fp);
unsigned char* ImageSize;
ImageSize = new unsigned char;
int x, y, val, xx, yy, temp;
for (y = 1; y < m_nHeight - 1; y++)
{
for (x = 1; x < m_nWidth - 1; x++)//由于使用3*3的结构元素,防止越界,不处理最左边和最右边的的像素
{
val = 0;
for (int j = 0; j < 2; j++)
{
yy = y + j - 1;
for (int i = 0; i < 2; i++)
{
xx = x + i - 1;
if (m_pImage[(xx + yy * m_nWidth) * 3 + yy * num] > val)//因为结构元素都是0,所以原图像中各点与对应结构元素想加还是原图像本身,
//找和的最大值作为点(x,y)的灰度
{
val = m_pImage[(xx + yy * m_nWidth) * 3 + yy * num];
}
}
}
ImageSize[(x + y * m_nWidth) * 3 + y * num] = unsigned char(val);
ImageSize[(x + y * m_nWidth) * 3 + y * num + 1] = unsigned char(val);
ImageSize[(x + y * m_nWidth) * 3 + y * num + 2] = unsigned char(val);
}
}
fwrite(ImageSize, m_nImage, 1, fpw);
fclose(fp);
fclose(fpw);
}
要修改代码以处理TIF格式的1位或8位色彩模式的二值图,可以使用OpenCV库来简化操作。主要思路是通过OpenCV读取TIF文件并进行膨胀处理,最终将结果保存回TIF文件。以下是修改后的代码:
首先,确保在项目中配置了OpenCV库。
#include <opencv2/opencv.hpp>
#include <iostream>
void processTif() {
// 使用OpenCV读取TIF图像
cv::Mat image = cv::imread("input.tif", cv::IMREAD_UNCHANGED);
if(image.empty()) {
std::cout << "无法打开文件!" << std::endl;
return;
}
// 确保图像是8位或1位二值图
if(image.type() != CV_8UC1 && image.type() != CV_8UC3) {
std::cout << "图像类型不兼容!" << std::endl;
return;
}
// 创建一个膨胀操作的结构元素 (3x3)
cv::Mat element = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3));
cv::Mat result;
// 对图像进行膨胀操作
cv::dilate(image, result, element);
// 保存处理后的图像
if(!cv::imwrite("output.tif", result)) {
std::cout << "保存图像失败!" << std::endl;
}
}
int main() {
processTif();
return 0;
}
### 说明:
1. **OpenCV库**: 使用OpenCV可以方便地处理多种格式的图像,包括TIF,并支持对一位或八位图像进行处理。
2. **cv::imread和cv::imwrite**: 分别用于读取和保存图像文件。`cv::IMREAD_UNCHANGED`确保读取的图像不受默认颜色转换的影响。
3. **cv::dilate**: 使用膨胀操作对图像进行处理,具体操作由`cv::getStructuringElement`函数定义的结构元素决定。
通过这种方式,处理图像的复杂度大大降低,并可以避免手动处理文件头、内存分配等低级细节。
以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。 FishC 发表于 2024-11-17 11:42
要修改代码以处理TIF格式的1位或8位色彩模式的二值图,可以使用OpenCV库来简化操作。主要思路是通过OpenCV ...
排除opencv方法,因为opencv方式打开特别大的图片时很费时间,所以想使用现在这种方式 cxnet 发表于 2024-11-17 11:45
排除opencv方法,因为opencv方式打开特别大的图片时很 ...
如果你想通过现有的方式读取和处理TIF格式的图像,而不依赖OpenCV,可以考虑使用libtiff库。libtiff是一个专门用于处理TIFF文件格式的库,可以高效读取和写入TIFF图像。
下面是一个如何使用libtiff来读取和处理TIF文件的示例代码,假设你已经安装并配置了libtiff:
#include <tiffio.h>
#include <stdlib.h>
#include <stdio.h>
void processTIFF(const char* inputFileName, const char* outputFileName) {
TIFF* tif = TIFFOpen(inputFileName, "r");
if (tif) {
uint32 width, height;
size_t npixels;
uint32* raster;
TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width);
TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height);
npixels = width * height;
raster = (uint32*)_TIFFmalloc(npixels * sizeof(uint32));
if (raster != NULL) {
if (TIFFReadRGBAImage(tif, width, height, raster, 0)) {
// 膨胀操作
for (uint32 y = 1; y < height - 1; y++) {
for (uint32 x = 1; x < width - 1; x++) {
// 获取像素值,进行膨胀
uint32 maxVal = 0;
for (int j = -1; j <= 1; j++) {
for (int i = -1; i <= 1; i++) {
uint32 currentVal = raster[(y + j) * width + (x + i)];
if (currentVal > maxVal) {
maxVal = currentVal;
}
}
}
raster = maxVal;
}
}
// 将处理后的图像写入新文件
TIFF* out = TIFFOpen(outputFileName, "w");
if (out) {
TIFFSetField(out, TIFFTAG_IMAGEWIDTH, width);
TIFFSetField(out, TIFFTAG_IMAGELENGTH, height);
TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, 4);
TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, 8);
TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
TIFFSetField(out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
TIFFSetField(out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
TIFFWriteEncodedStrip(out, 0, raster, npixels * sizeof(uint32));
TIFFClose(out);
}
}
_TIFFfree(raster);
}
TIFFClose(tif);
} else {
fprintf(stderr, "Could not open the specified TIFF file\n");
}
}
int main() {
processTIFF("input.tif", "output.tif");
return 0;
}
请注意,这是一个基础示例,处理的是32位RGBA TIFF图像。如果你要处理1位或8位的图像,你需要根据具体的TIFF图像格式更改读取和膨胀操作的方式。此外,为了成功编译和运行,你需要在编译时链接libtiff库。
以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。 FishC 发表于 2024-11-17 11:45
如果你想通过现有的方式读取和处理TIF格式的图像,而不依赖OpenCV,可以考虑使用libtiff库。libtiff是 ...
这里面怎样将它修改成2*2的结构元素进行膨胀 cxnet 发表于 2024-11-17 11:48
这里面怎样将它修改成2*2的结构元素进行膨胀
要使用2x2的结构元素进行膨胀,你需要遍历每个像素,并检查该像素及其右、下、和右下区域的像素值(因为2x2结构元素在平面上意味着要检查这些位置)。如果其中任一像素有非零值,那么中央像素就设置为最大值。在二值图像的情况下,这意味着任何“1”就使中心值成为“1”。
以下是使用libtiff库的示例代码,假设你已经安装并正确配置了libtiff库:
#include <tiffio.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <memory.h>
void processTIFF(const char* inputFileName, const char* outputFileName) {
TIFF* tif = TIFFOpen(inputFileName, "r");
if (!tif) {
printf("Could not open input file %s\n", inputFileName);
return;
}
uint32 width, height;
size_t nPixels;
uint32* raster;
TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width);
TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height);
nPixels = width * height;
raster = (uint32*)_TIFFmalloc(nPixels * sizeof(uint32));
if (!raster) {
printf("Memory allocation error\n");
TIFFClose(tif);
return;
}
// Read image data
if (!TIFFReadRGBAImage(tif, width, height, raster, 0)) {
printf("Could not read image\n");
_TIFFfree(raster);
TIFFClose(tif);
return;
}
// Creating output raster with the same size
uint32* outputRaster = (uint32*)_TIFFmalloc(nPixels * sizeof(uint32));
if (!outputRaster) {
printf("Memory allocation error\n");
_TIFFfree(raster);
TIFFClose(tif);
return;
}
// Copy the original image before processing
memcpy(outputRaster, raster, nPixels * sizeof(uint32));
// Dilation with a 2x2 structure
for (uint32 y = 0; y < height - 1; y++) {
for (uint32 x = 0; x < width - 1; x++) {
int isSet = 0;
uint32 idx = y * width + x;
// Examine 2x2 area
isSet |= (raster & 0xFF); // pixel at (x, y)
isSet |= (raster & 0xFF); // pixel at (x+1, y)
isSet |= (raster & 0xFF); // pixel at (x, y+1)
isSet |= (raster & 0xFF); // pixel at (x+1, y+1)
if (isSet) {
// Set gray-scale to max (assuming 8-bit per channel grayscale)
outputRaster = 0xFFFFFFFF; // white: RGBA all channels max
outputRaster = 0xFFFFFFFF;
outputRaster = 0xFFFFFFFF;
outputRaster = 0xFFFFFFFF;
}
}
}
TIFF* out = TIFFOpen(outputFileName, "w");
if (!out) {
printf("Could not open output file %s\n", outputFileName);
_TIFFfree(raster);
_TIFFfree(outputRaster);
TIFFClose(tif);
return;
}
TIFFSetField(out, TIFFTAG_IMAGEWIDTH, width);
TIFFSetField(out, TIFFTAG_IMAGELENGTH, height);
TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, 4);
TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, 8);
TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
TIFFSetField(out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
TIFFSetField(out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
tsize_t lineBytes = 4 * width; // RGBA image
unsigned char* buf = NULL; // buffer used to store the horizontal line
// Allocate buffer for 1 line of span
buf = (unsigned char*)_TIFFmalloc(lineBytes);
if (!buf) {
printf("Memory allocation error\n");
_TIFFfree(raster);
_TIFFfree(outputRaster);
TIFFClose(tif);
TIFFClose(out);
return;
}
// Write the image
for (uint32 row = 0; row < height; row++) {
memcpy(buf, &outputRaster[(height-row-1)*width], lineBytes);
if (TIFFWriteScanline(out, buf, row, 0) < 0) {
break;
}
}
_TIFFfree(buf);
_TIFFfree(raster);
_TIFFfree(outputRaster);
TIFFClose(tif);
TIFFClose(out);
}
int main() {
processTIFF("input.tif", "output.tif");
return 0;
}
在这个示例中,遍历图像时,检查当前位置及其上、左、右上方像素的值。若任一位置为1,表示需要设置结果位置为255(即白色)。注意,这段代码是基于假设图像为8位灰度(每像素一个字节),需要根据实际的TIFF格式做调整,比如样本字节大小和像素格式。
以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。 FishC 发表于 2024-11-17 11:49
要使用2x2的结构元素进行膨胀,你需要遍历每个像素,并检查该像素及其右、下、和右下区域的像素值(因 ...
为什么这段代码里的2*2的结构元素膨胀后比opencv的2*2的结构元素所膨胀得要多差不多1像素呢?相当于opencv的3*3的结构元素膨胀效果,我要把它减为1*1结构元素应该修改哪个参数 cxnet 发表于 2024-11-17 11:55
为什么这段代码里的2*2的结构元素膨胀后比opencv的2*2 ...
这段代码的膨胀操作实际上是基于2x2邻域(正方形顶部左角开始),它影响的区域是比2x2邻域要多的。这是因为代码遍历了邻近像素并以相对简单的方式扩展了图像。
如果要缩小为1x1结构元素,即简单的自扩展(实际上不扩展任何像素),那么实际上不会改变图像,因为1x1结构元素等同于对像素自身进行检查,没有邻域的影响。所以“1x1膨胀”不会对图像产生变化。
对于只考虑2x2实际的膨胀:
1. 检查每个单独像素而不是树立看整个2x2局部。
2. 确保只有自身参与"扩张",这意味着只修改特定点。
但是,如果你的意思是将不同形状的结果生成,查看代码时注意:
for (int j = 0; j < 2; j++) {
yy = y + j - 1;
for (int i = 0; i < 2; i++) {
xx = x + i - 1;
if (m_pImage > val) {
val = m_pImage;
}
}
}
在上面这个片段中,如果你想控制邻域的大小和形状,调整这两个for循环即可。`1x1`不改变任何邻域,你可以直接输出原始图像而无需额外处理,或者移除所有的`val`赋值步骤,保留`outputRaster`生成部分即可。
如果你遇到了图形扩张结果不是预期问题,可能是邻域处理中访问过多外背景,因此要更谨慎的设置起始和边界条件,如果您需要精细化,使用专业工具(如OpenCV的形态学操作)可能会更合适。但在`libtiff`仅用于读取和原生操作部分,它不提供OpenCV复杂操作。
以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。 FishC 发表于 2024-11-17 11:55
这段代码的膨胀操作实际上是基于2x2邻域(正方形顶部左角开始),它影响的区域是比2x2邻域要多的。这是 ...
用这种方式试了一下大尺寸的TIF图片会出错,看来这种方式也只能处理比较小的图片。
用CImage方式加载TIF二值8位或者1位二值图进行2*2结构元素进行膨胀应该怎样写代码。想试试这种方式是否可行 cxnet 发表于 2024-11-17 12:11
用这种方式试了一下大尺寸的TIF图片会出错,看来这种 ...
使用 `CImage` 类来处理 TIFF 图像可以利用 GDI+ 来进行图像加载和处理,从而支持较大的图片。下面是一个使用 `CImage` 和 GDI+ 实现简单膨胀的示例代码:
#include <afxwin.h> // MFC core and standard components
#include <gdiplus.h> // GDI+
#pragma comment (lib, "gdiplus.lib")
using namespace Gdiplus;
void ProcessTIFwithCImage(const wchar_t* inputFileName, const wchar_t* outputFileName) {
// Initialize GDI+
GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
CImage image;
HRESULT hr = image.Load(inputFileName);
if (FAILED(hr)) {
printf("Failed to load image\n");
return;
}
int width = image.GetWidth();
int height = image.GetHeight();
// Create a new image for the output
CImage outputImage;
outputImage.Create(width, height, 8);
// Iterate through each pixel, excluding the boundary pixels
for (int y = 0; y < height - 1; y++) {
for (int x = 0; x < width - 1; x++) {
// Check the 2x2 neighborhood for dilation
BYTE pixelValue = image.GetPixel(x, y) == 0xFFFFFF ? 1 : 0; // Assuming binary white is the forepixel
// Check each pixel in 2x2 area
if (pixelValue == 0) {
if ((x + 1 < width && image.GetPixel(x + 1, y) == 0xFFFFFF) ||
(y + 1 < height && image.GetPixel(x, y + 1) == 0xFFFFFF) ||
(x + 1 < width && y + 1 < height && image.GetPixel(x + 1, y + 1) == 0xFFFFFF)) {
pixelValue = 1;
}
}
// Set the result pixel value
COLORREF color = pixelValue ? RGB(255, 255, 255) : RGB(0, 0, 0);
outputImage.SetPixel(x, y, color);
}
}
// Save the processed image to a new file
outputImage.Save(outputFileName);
// Cleanup GDI+
GdiplusShutdown(gdiplusToken);
}
int main() {
ProcessTIFwithCImage(L"input.tif", L"output.tif");
return 0;
}
### 代码说明:
1. **初始化GDI+**:在使用任何 GDI+ 功能之前,必须进行初始化。
2. **加载图像**:使用 `CImage` 来加载 TIFF 文件。
3. **创建输出图像**:创建一个新的 `CImage` 对象来存储输出结果。
4. **处理图像**:通过遍历图像,为每个非边界像素检查其自身及相邻像素的值,执行膨胀操作。
5. **保存结果**:最后将处理后的图像保存为一个新的 TIFF 文件。
请注意,确保使用 `CImage` 和 GDI+ 方法时,处理二值图像时要保证图像是用正确的格式(比如前景为白色 `0xFFFFFF` 和背景为黑色 `0x000000`)。
以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
页:
[1]