essentially, I'm making a class that takes a BMP file for the constructor. From THIS POST I get all of the header data out of the way and then read RGB data into a vector. I then calculate the intensities as 0.25R + 0.5G + 0.25B. I put these numbers into a space-separated file, line by line. With the original above my result below and Using GNUPlot to open and plot the image gives me this result.
original
distortion
As you can see, the right side of the image is consistently being wrapped around further as the image is written to file (or somewhere before this process). I've pasted the code below, any help?
std::vector<char> MImage::readBMP(std::string const file){
static constexpr size_t HEADER_SIZE = 54;
std::ifstream bmp(file, std::ios::binary);
std::array<char, HEADER_SIZE> header;
bmp.read(header.data(), header.size());
auto fileSize = *reinterpret_cast<uint32_t*>(&header[2]);
auto dataOffset = *reinterpret_cast<uint32_t*>(&header[10]);
auto width = *reinterpret_cast<uint32_t*>(&header[18]);
auto height = *reinterpret_cast<uint32_t*>(&header[22]);
auto depth = *reinterpret_cast<uint16_t*>(&header[28]);
/*
std::cout << "fileSize: " << fileSize << std::endl;
std::cout << "dataOffset: " << dataOffset << std::endl;
std::cout << "width: " << width << std::endl;
std::cout << "height: " << height << std::endl;
std::cout << "depth: " << depth << "-bit" << std::endl;
*/
std::vector<char> img(dataOffset - HEADER_SIZE);
//bmp.read(img.data(), img.size());
auto dataSize = ((width * 3 + 3) & (~3)) * height;
img.resize(dataSize);
bmp.read(img.data(), img.size());
char temp = 0;
for (int i = dataSize - 4; i >= 0; i -= 3)
{
temp = img[i];
img[i] = img[i + 2];
img[i + 2] = temp;
}
// Convert to intensity
int k = 0;
int size = (int)img.size();
for (int j = 0; k+2 < size; j++)
{
//0.25B + 0.5G + 0.25R
img[j] = ((abs(img[k]) >> 2) + (abs(img[k + 1]) >> 1) + (abs(img[k + 2]) >> 2));
//OutputDebugStringA((to_string(img[j]) + "\n").c_str());
k += 3;
}
img.resize(dataSize / 3);
//OutputDebugStringA((to_string(img.size()) + "\n").c_str());
int a, b, c = 0;
//Testing #img data
ofstream TestPic;
TestPic.open("testpic.txt");
for (a = 0; a < HEIGHT; a++) {
for (b = 0; b < WIDTH; b++) {
TestPic << (int)img[c];
if (b < WIDTH-1) {
TestPic << " ";
}
c++;
}
TestPic << "\n";
}
TestPic.close();
return img; }
GNUPlot command: plot [0:630] [0:354] 'testpic.txt' matrix with image pixels
The problem you are seeing is caused by improper data alignment. Each scanline of .bmp file must have a byte-size divisible by 4. You are calculating the input data size correctly with this line:
auto dataSize = ((width * 3 + 3) & (~3)) * height;
However, while converting the img array you do not compensate/throw away the padding at the end of each scanline.
The best advice is either to use a standard bmp loader/converter like the one in STB libraries (the stb_image.h file) or, if you want to do it yourself, allocate the other array (img2 or something like that) and iterate img array scanline by scanline, writing greyscale values to img2.
By the way, this answer, which you have mentioned, contains a solution for your exact problem (it is called the "padding fix").
Related
i have found this Loading a tga/bmp file in C++/OpenGL, it works flawless and would like to use it in my project. however my project requires a RGB struct to modify the pixels buffer.
glDrawPixels(win_height, win_width, GL_RGB, GL_FLOAT, myBuffer);
it needs some changes to make it work in my project.
typedef union PixelInfo
{
std::uint32_t Colour;
struct
{
float b, g, r, a;
};
} *PPixelInfo;
class BMP
{
private:
std::uint32_t width, height;
std::uint16_t BitsPerPixel;
std::vector<std::uint8_t> Pixels;
public:
BMP(const char* FilePath);
std::vector<std::uint8_t> GetPixels() const {return this->Pixels;}
std::uint32_t GetWidth() const {return this->width;}
std::uint32_t GetHeight() const {return this->height;}
bool HasAlphaChannel() {return BitsPerPixel == 32;}
};
BMP::BMP(const char* FilePath)
{
std::fstream hFile(FilePath, std::ios::in | std::ios::binary);
if (!hFile.is_open()) throw std::invalid_argument("Error: File Not Found.");
hFile.seekg(0, std::ios::end);
std::size_t Length = hFile.tellg();
hFile.seekg(0, std::ios::beg);
std::vector<std::uint8_t> FileInfo(Length);
hFile.read(reinterpret_cast<char*>(FileInfo.data()), 54);
if(FileInfo[0] != 'B' && FileInfo[1] != 'M')
{
hFile.close();
throw std::invalid_argument("Error: Invalid File Format. Bitmap Required.");
}
if (FileInfo[28] != 24 && FileInfo[28] != 32)
{
hFile.close();
throw std::invalid_argument("Error: Invalid File Format. 24 or 32 bit Image Required.");
}
BitsPerPixel = FileInfo[28];
width = FileInfo[18] + (FileInfo[19] << 8);
height = FileInfo[22] + (FileInfo[23] << 8);
std::uint32_t PixelsOffset = FileInfo[10] + (FileInfo[11] << 8);
std::uint32_t size = ((width * BitsPerPixel + 31) / 32) * 4 * height;
Pixels.resize(size);
hFile.seekg (PixelsOffset, std::ios::beg);
hFile.read(reinterpret_cast<char*>(Pixels.data()), size);
hFile.close();
}
int main()
{
BMP info = BMP("Fixedsys16x28.bmp");
//info.
std::cout << "getwidth: " << info.GetWidth() << endl;
std::cout << "getheight: " << info.GetHeight()<< endl;
// for(auto i : info.GetPixels()){
// //float i_float = float(i);
// //float res = i_float / 15.0;
// //std::cout << std::hex << (int)i << " " << endl;
// std::cout << setprecision(2) << fixed << (float) i / 255 << " " << endl;
// }
std::cout << endl;
std::cout << "size: " << info.GetPixels().size() << endl;
std::cout << "alpha: " << info.HasAlphaChannel() << endl;
std::cout << setprecision(2) << fixed;
for(int i = 0; i < static_cast<int>(info.GetPixels().size()); i++){
for(int j = 0; j < 3; j++){
if(j == 0){
std::cout << (float) info.GetPixels()[i]/ 255 << " ";
}
else if(j == 1){
std::cout << (float) info.GetPixels()[i] / 255 << " ";
}
else{
std::cout << (float) info.GetPixels()[i] / 255;
}
}
std::cout << endl;
}
getchar();
GLuint texture = 0;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, info.HasAlphaChannel() ? GL_RGBA : GL_RGB, info.GetWidth(), info.GetWidth(), 0, info.HasAlphaChannel() ? GL_BGRA : GL_BGR, GL_UNSIGNED_BYTE, info.GetPixels().data());
}
how to change this line of code?
hFile.read(reinterpret_cast<char*>(Pixels.data()), size);
so that vector gets filed with ...
typedef union PixelInfo
{
std::uint32_t Colour;
struct
{
float B, G, R, A;
};
} *PPixelInfo;
collections.
after changing the setup of vector off course or use another.
what kind of of method / function, could replace Pixels.data() , so it collect these 4 bytes and assembles them accordingly in the type of struct PixelInfo?
since Pixels.data() basically provide a pointer to the pixel vector.
how does a method that can perform the requested task look like?
collect 4 bytes of data and format them accordingly and put them in a vector<PixelInfo> while converting "std::uint8_t" into float. fast and efficiently.
it should take this in consideration "info.HasAlphaChannel()".
the accompanied image data is:
512×84 and the pixel vector size is "129024".
43008×3 bytes = 129024.
i made this loop on the pixel vector:
std::cout << setprecision(2) << fixed;
for(int i = 0; i < static_cast<int>(info.GetPixels().size()); i++){
for(int j = 0; j < 3; j++){
if(j == 0){
std::cout << (float) info.GetPixels()[i]/ 255 << " ";
}
else if(j == 1){
std::cout << (float) info.GetPixels()[i] / 255 << " ";
}
else{
std::cout << (float) info.GetPixels()[i] / 255;
}
}
std::cout << endl;
}
it seams to have worked correctly and even the last line contains 3 "bytes" of data.
this routine takes, like 20 seconds for an image 400 x 400 px.
vector<PixelInfo> pixelStore (info->GetPixels().size() / 3);
int counter = 0;
for(int i = 0; i < size; i+=3){
PixelInfo temp;
temp.r = 0;
temp.g = 0;
temp.b = 0;
for(int j = 0; j < 3; j++){
if(j == 0){
temp.r = info->GetPixels()[i + j];
}
else if(j == 1){
temp.g = info->GetPixels()[i + j];
}
else{
temp.b = info->GetPixels()[i + j];
}
if(j == 2){
//pixelStore.push_back(temp);
pixelStore[counter] = temp;
counter++;
}
}
}
Your code shows std::vector<std::uint8_t> Pixels; which is a sequence of 8-bit pixels I suppose. You want a vector of PixelInfo instead? Now does that structure match the format of bytes in the file? If that's the case, then what's the problem?
If the bytes in the file match the layout of your structure (including the machine's Endian!) just do it the same way:
vector<PixelInfo> Pixels;
size_t pixels_to_read = ....??? ;
Pixels.resize(pixels_to_read);
hFile.read (reinterpret_cast<char*>(Pixels.data()), pixels_to_read*sizeof(PixelInfo));
update
collect 4 bytes of data and format them accordingly and put them in a vector while converting "std::uint8_t" into float. fast and efficiently.
std::byte buf[4];
hFile.read (reinterpret_cast<char*>(buf),4); // read 4 bytes from file
PixelInfo px;
px.R = buf[0]; // converts 8-bit integer to float
px.G = buf[1];
px.B = buf[2];
px.A = buf[3];
Note that your PixelInfo union doesn't make sense -- how does the 32-bit color match the layout of the 4 32-bit components? Furthermore, I don't think that definition is legal, as there is no such thing as an anonymous struct. If that compiles, it must be a compiler extension.
As for doing it fast :
Read in a lot at a time, rather than one pixel. A whole row is good, if it's not practical to read the entire file into memory. Then you just step along the buffer you had loaded.
You can hope that the 4 individual statements get auto-vectorized by the optimizer. If you have a tight and simple loop around just that part (to process a whole row) you might get the compiler to vectorize it.
The fact that you have to write 4 separate statements because the left hand side uses different names rather than an index should not affect the overall speed.
20 seconds for a 400×400 pixel image? I would think it would be instantaneous. I have experience loading/converting/decoding graphics files, having written a library for DOS and bare metal (16-bit x86 code) back in the early '90's. You might try benchmarking code that only does this conversion listed above, to see if that's your bottleneck or not. Look at the code generated (in the debugger, or using Compiler Explorer) to see if it's vectorizing. Look into calling the vector primitives intrinsic instructions directly, if your compiler has that available. See if you're using all the right compiler optimization flags.
I am trying to read an RGB image and convert it to 1D array. When printing the values, I understand that the logic I have written for conversion is not correct. Can someone help me with this please? Also, when I am trying to define image_array, it is giving me an error.
Expression must have constant value.
I have posted the code below.
//reading the images
Mat img_rev = imread("C:/Users/20181217/Desktop/images/imgs/output_rev.png");
cvtColor(img_rev, img_rev, COLOR_BGR2RGB);
//get the image height,width and number of channles to convert into an array
int const img_height = img_rev.rows;
int const img_width = img_rev.cols;
int const img_channels = img_rev.channels();
//printing out the dimenesions
cout << img_height << ", " << img_width << ", " << img_channels; //256,512,3
//starting the conversion to array
uchar image_array[256 * 512 * 3];
//uchar image_array[img_rev.rows * img_rev.cols * img_rev.channels()]; error:expression must have a constant value
//uchar image_array[img_height * img_width * img_channels]; error:expression must have a constant value
for (int i = 0; i < img_rev.rows; i++)
{
for (int j = 0; j < img_rev.cols; j++)
{
if(i==200 && j==200)
cout << endl << "value at (200,200) of green in MAT is :" << (int)img_rev.at<Vec3b>(i, j)[1] << endl; //printing the value at (200,200) of green channel
}
}
//conversion from image to 1d array
for (int i = 0; i < img_rev.rows; i++)
{
for (int j = 0; j < img_rev.cols; j++)
{
image_array[(i*img_rev.rows) + (j * 3)] = img_rev.at<Vec3b>(i, j)[0]; //R
image_array[(i*img_rev.rows) + (j * 3) + 1] = img_rev.at<Vec3b>(i, j)[1]; //G
image_array[(i*img_rev.rows) + (j * 3) + 2] = img_rev.at<Vec3b>(i, j)[2]; //B
}
}
cout << endl << "value at (200,200) of green in array is :" << (int)image_array[(200*img_rev.cols) + 200 +1];
cout << endl << "done";
waitKey(100000);
I would be really grateful if someone can provide me some assistance with this.
Thanks in advance.
If the array does not have a fixed-size, like in your example, you should use dynamically allocated array. Declaring uchar* image_array = new uchar[img_rev.total() * img_rev.channels()] can be a solution but you need to delete it manually to free memory when it is used no more.
In order not to deal with keeping track of deletion, I suggest using std::vector.
std::vector<uchar> image_array(img_rev.total() * img_rev.channels());
And you can use your method once the array is dynamically allocated.
There is an easier method for converting cv::Mat to std::vector. In you case, since img_rev is created by imread, we are sure that the data is continuous, so we can do the following:
std::vector<uchar> image_array = img_rev.data;
i am trying to convert openvino c++ object_detection_ssd sample to dll library, so that i can use it in my c# application.
below is my code c++ code to export function
__declspec(dllexport) void Classify_Image(unsigned char* img_pointer, long data_len,
char* out_result, int length_of_out_result, int top_n_results)
{
std::vector<unsigned char> inputImageBytes(img_pointer, img_pointer + data_len);
cv::Mat image = cv::imdecode(inputImageBytes,cv::IMREAD_COLOR);
//cv::imwrite("lala.jpg", image);
if (inputInfo == nullptr) {
initialize();
}
// --------------------------- 8. Create infer request -------------------------------------------------
//slog::info << "Create infer request" << slog::endl;
InferRequest infer_request = executable_network.CreateInferRequest();
// -----------------------------------------------------------------------------------------------------
std::vector<std::shared_ptr<unsigned char>> imagesData, originalImagesData;
std::vector<size_t> imageWidths, imageHeights;
//FormatReader::ReaderPtr reader("C:\\Users\\Sam\\Desktop\\la.jpg");
cv::Mat dst;
cv::resize(image, dst, cv::Size(400, 225));
cv::imwrite("lala_m.jpg", dst);
//std::shared_ptr<unsigned char> originalData(image.data);
std::shared_ptr<unsigned char> originalData(image.data);
std::shared_ptr<unsigned char> data1(dst.data);
//
originalImagesData.push_back(originalData);
imagesData.push_back(data1);
imageWidths.push_back(1280);
imageHeights.push_back(720);
if (imagesData.empty()) throw std::logic_error("Valid input images were not found!");
size_t batchSize = network.getBatchSize();
if (batchSize != imagesData.size()) {
slog::warn << "Number of images " + std::to_string(imagesData.size()) + \
" doesn't match batch size " + std::to_string(batchSize) << slog::endl;
batchSize = std::min(batchSize, imagesData.size());
slog::warn << "Number of images to be processed is " << std::to_string(batchSize) << slog::endl;
}
///** Creating input blob **/
Blob::Ptr imageInput = infer_request.GetBlob(imageInputName);
///** Filling input tensor with images. First b channel, then g and r channels **/
MemoryBlob::Ptr mimage = as<MemoryBlob>(imageInput);
if (!mimage) {
slog::err << "We expect image blob to be inherited from MemoryBlob, but by fact we were not able "
"to cast imageInput to MemoryBlob" << slog::endl;
return;
}
//// locked memory holder should be alive all time while access to its buffer happens
auto minputHolder = mimage->wmap();
size_t num_channels = mimage->getTensorDesc().getDims()[1];
size_t image_size = mimage->getTensorDesc().getDims()[3] * mimage->getTensorDesc().getDims()[2];
unsigned char *data = minputHolder.as<unsigned char *>();
/** Iterate over all input images **/
for (size_t image_id = 0; image_id < std::min(imagesData.size(), batchSize); ++image_id) {
/** Iterate over all pixel in image (b,g,r) **/
for (size_t pid = 0; pid < image_size; pid++) {
/** Iterate over all channels **/
for (size_t ch = 0; ch < num_channels; ++ch) {
/** [images stride + channels stride + pixel id ] all in bytes **/
data[image_id * image_size * num_channels + ch * image_size + pid] = imagesData.at(image_id).get()[pid*num_channels + ch];
}
}
}
if (imInfoInputName != "") {
Blob::Ptr input2 = infer_request.GetBlob(imInfoInputName);
auto imInfoDim = inputsInfo.find(imInfoInputName)->second->getTensorDesc().getDims()[1];
/** Fill input tensor with values **/
MemoryBlob::Ptr minput2 = as<MemoryBlob>(input2);
if (!minput2) {
slog::err << "We expect input2 blob to be inherited from MemoryBlob, but by fact we were not able "
"to cast input2 to MemoryBlob" << slog::endl;
return;
}
// locked memory holder should be alive all time while access to its buffer happens
auto minput2Holder = minput2->wmap();
float *p = minput2Holder.as<PrecisionTrait<Precision::FP32>::value_type *>();
for (size_t image_id = 0; image_id < std::min(imagesData.size(), batchSize); ++image_id) {
p[image_id * imInfoDim + 0] = static_cast<float>(inputsInfo[imageInputName]->getTensorDesc().getDims()[2]);
p[image_id * imInfoDim + 1] = static_cast<float>(inputsInfo[imageInputName]->getTensorDesc().getDims()[3]);
for (size_t k = 2; k < imInfoDim; k++) {
p[image_id * imInfoDim + k] = 1.0f; // all scale factors are set to 1.0
}
}
}
// -----------------------------------------------------------------------------------------------------
// --------------------------- 10. Do inference ---------------------------------------------------------
slog::info << "Start inference" << slog::endl;
infer_request.Infer();
// -----------------------------------------------------------------------------------------------------
// --------------------------- 11. Process output -------------------------------------------------------
slog::info << "Processing output blobs" << slog::endl;
const Blob::Ptr output_blob = infer_request.GetBlob(outputName);
MemoryBlob::CPtr moutput = as<MemoryBlob>(output_blob);
if (!moutput) {
throw std::logic_error("We expect output to be inherited from MemoryBlob, "
"but by fact we were not able to cast output to MemoryBlob");
}
// locked memory holder should be alive all time while access to its buffer happens
auto moutputHolder = moutput->rmap();
const float *detection = moutputHolder.as<const PrecisionTrait<Precision::FP32>::value_type *>();
std::vector<std::vector<int> > boxes(batchSize);
std::vector<std::vector<int> > classes(batchSize);
///* Each detection has image_id that denotes processed image */
std::string result = "OB_DATA=";
int num_detect = 0;
for (int curProposal = 0; curProposal < maxProposalCount; curProposal++) {
auto image_id = static_cast<int>(detection[curProposal * objectSize + 0]);
if (image_id < 0 ) {
slog::info << "ends with break "<<slog::endl;
break;
}
float confidence = detection[curProposal * objectSize + 2];
auto label = static_cast<int>(detection[curProposal * objectSize + 1]);
auto xmin = static_cast<int>(detection[curProposal * objectSize + 3] * imageWidths[image_id]);
auto ymin = static_cast<int>(detection[curProposal * objectSize + 4] * imageHeights[image_id]);
auto xmax = static_cast<int>(detection[curProposal * objectSize + 5] * imageWidths[image_id]);
auto ymax = static_cast<int>(detection[curProposal * objectSize + 6] * imageHeights[image_id]);
std::cout << "[" << curProposal << "," << label << "] element, prob = " << confidence <<
" (" << xmin << "," << ymin << ")-(" << xmax << "," << ymax << ")" << " batch id : " << image_id;
if (confidence > 0.5) {
num_detect += 1;
result += std::to_string(confidence);
result += ","+ std::to_string(label);
result += "," + std::to_string(xmin);
result += "," + std::to_string(ymin);
result += "," + std::to_string(xmax);
result += "," + std::to_string(ymax);
/** Drawing only objects with >50% probability **/
classes[image_id].push_back(label);
boxes[image_id].push_back(xmin);
boxes[image_id].push_back(ymin);
boxes[image_id].push_back(xmax - xmin);
boxes[image_id].push_back(ymax - ymin);
//std::cout << " WILL BE PRINTED!";
/*std::cout << std::endl;*/
//slog::info << " add prediction" << slog::endl;
}
result += ";";
std::cout << std::endl;
}
data1.reset();
originalData.reset();
//dst.release();
//image.release();
length_of_out_result = (int)result.size();
std::copy(result.begin(), result.end(), out_result);
out_result[std::min(length_of_out_result - 1, (int)result.size())] = 0;
std::cout << "end code"<<std::endl;
}
}
in the code above i am trying to decode my byte array which i send from c# to opencv mat and run inference on mat object, so when i call this function from c# it works fine but after printing "end code" line it gives error in my c# application, below is my code in c#, my c# application can't print Console.WriteLine("after call"); and in the visual studio output i can see last line printed by c++ function which is "end code"
[DllImport("object_detection_sample_ssd.dll", CallingConvention = CallingConvention.Cdecl)]
static extern void Classify_Image(byte[] img, long data_len, StringBuilder out_result, int out_result_length, int top_n_results = 2);
private void button3_Click(object sender, EventArgs e)
{
byte[] result = new byte[200];
Image img = Image.FromFile(#"C:\Users\Sam\Desktop\la.jpg");
ImageFormat fmt = new ImageFormat(img.RawFormat.Guid);
var imageCodecInfo = ImageCodecInfo.GetImageEncoders().FirstOrDefault(codec => codec.FormatID == img.RawFormat.Guid);
//this is for situations, where the image is not read from disk, and is stored in the memort(e.g. image comes from a camera or snapshot)
if (imageCodecInfo == null)
{
fmt = ImageFormat.Jpeg;
}
//Image img = Image.FromFile(#"");
using (MemoryStream ms = new MemoryStream())
{
img.Save(ms, fmt);
byte[] image_byte_array = ms.ToArray();
int len_result=300;
int STRING_MAX_LENGTH1 = 300;
StringBuilder str1 = new StringBuilder(STRING_MAX_LENGTH1);
Classify_Image(image_byte_array, ms.Length, str1, len_result, 2);
Console.WriteLine("after call");
}
Console.WriteLine("even after using");
Console.WriteLine("output ="+ ASCIIEncoding.ASCII.GetString(result));
}
i dont know what is wrong with that, in the original example of openvino toolkit there is a FormatReader.h file which is used to load image from image file path, i have tried with passing image file name and use FormatReader as original and it works. FormatReader https://github.com/openvinotoolkit/openvino/tree/master/inference-engine/samples/common/format_reader
please help!
I suggest you refer to Hello Classification C++ Sample, which loads image from Mat for inferencing. The main.cpp file is available at the following link:
https://github.com/openvinotoolkit/openvino/blob/master/inference-engine/samples/hello_classification/main.cpp
I have this program (c++) that calculates two variables values in a while cycle. I'm trying to wrote these values in a text file. Now I want to write the 5 values of my lforce variable in one line of the text file and the 5 values of my rforce variable in the other line.
How can I do that?
int i = 5;
int a2dVal = 0;
int a2dChannel = 0;
unsigned char data[3];
float g = 9.8;
int fsensor1;
int fsensor2;
int fsensor3;
int fsensor4;
int fsensor5;
int fsensor6;
float vsensor;
int lforce;
int rforce;
float vref = 2.5;
float vin = 3.3;
ofstream myfile ("/var/www/html/Sensors/all.txt");
if (myfile.is_open())
{
while(i > 0)
{
data[0] = 1; // first byte transmitted -> start bit
data[1] = 0b1000000000 |( ((a2dChannel & 9) << 4)); // second byte transmitted -> (SGL/DIF = 1, D2=D1=D0=0)
data[2] = 0; // third byte transmitted....don't care
a2d.spiWriteRead(data, sizeof(data) );
a2dVal = 0;
a2dVal = (data[1]<< 10) & 0b110000000000; //merge data[1] & data[2] to get result
a2dVal |= (data[2] & 0x0f);
sleep(1);
vsensor = (vref*a2dVal)/1024;
fsensor1 = ((vsensor/0.1391)-0.0329)*g;
fsensor2 = ((vsensor/0.1298)+0.1321)*g;
fsensor3 = ((vsensor/0.1386)+0.0316)*g;
fsensor4 = ((vsensor/0.1537)-0.0524)*g;
fsensor5 = ((vsensor/0.1378)+0.0922)*g;
fsensor6 = ((vsensor/0.1083)-0.0096)*g;
lforce = fsensor4 + fsensor5 + fsensor6;
rforce = fsensor1 + fsensor2 + fsensor3;
cout << lforce << " ";
cout << rforce << " ";
i--;
}
myfile << lforce << " " << rforce << " "; // here I want to write the variables in different lines of the text file
}
myfile.close();
return 0;
}
If you want to do this by manipulating file's cursor, you may use fseek and rewind functions. But I think it's unreasonbly difficult and much easier will be create 2 arrays and do somethig like this:
lforce = fsensor4 + fsensor5 + fsensor6;
lforceArray[5-i] = lforce;
rforce = fsensor1 + fsensor2 + fsensor3;
rforceArray[5-i] = rforce;
And then just write these arrays into the file.
I'm trying to read painted 16x16 bmp, but there is no 1 pixel = 3 bits (RGB). Even if first 4-5 lines is white and the rest is black the document is still full of 255 255 255 for each pixel.
In my case I need to show this image in console by analyzing RGB layers of each pixel but have a lot of trouble with it.
int main()
{
FILE* f = fopen("image.bmp", "rb");
unsigned char info[54];
fread(info, sizeof(unsigned char), 54, f); // read the 54-byte header
// extract image height and width from header
int width = *(int*)&info[18];
int height = *(int*)&info[22];
int size = 3 * width * height;
unsigned char * data = new unsigned char[size]; // allocate 3 bytes per pixel
fread(data, sizeof(unsigned char), size, f); // read the rest of the data at once
fclose(f);
for (int i = 0; i < size; i += 3)
{
unsigned char tmp = data[i];
data[i] = data[i + 2];
data[i + 2] = tmp;
}
unsigned int * byteData = new unsigned int[size];
for (int i = 0; i <= size; i++)
{
byteData[i] = (int) data[i];
}
for (int i = 0; i <= size / 3; i++)
{
cout << i << ".\t" << byteData[i] << "\t" << byteData[i + 1] << "\t" << byteData[i + 2] << endl;
}
cout << endl;
cout << "=======================" << endl;
for (int j = 0; j < width; j++)
{
cout << j + 1 << ".\t";
for (int i = 0; i < height; i++)
{
//if ((int)data[j * width + i] >= 100 && (int)data[j * width + i + 1] >= 100 && (int)data[j * width + i + 2] >= 100)
if (((int) data[j * width + i] + (int) data[j * width + i + 1] + (int) data[j * width + i + 2]) / 3 <= 170)
cout << " ";
else cout << "*";
}
cout << endl;
}
getchar();
return 0;
}
As I think problem with byte sequenses and reading memory frome garbage, but if you could explain where is leak?
The solution is next: bmp should be created with 24 bpp and top-down row order.
Correct code is for 16x16 bitmap:
#include <iostream>
using namespace std;
unsigned char* readBMP(char* filename);
int main()
{
unsigned char * data = readBMP("winLogo.bmp");
int size = 16*16*3;
unsigned int * byteData = new unsigned int[size];
for (int i = 0; i <= size; i++)
{
byteData[i] = (int)data[i];
}
int k = 0;
//uncomment to write a line of RGB values
//for (int i = 0; i < size; i += 3)
//{
// cout << k+1 << ".\t" << byteData[i] << "\t" << byteData[i + 1] << "\t" << byteData[i + 2] << endl;
// k++;
//}
for (int i = 0; i < size; i+= 3)
{
if (i % 16*3 == 0)
{
cout << endl << (i/(16*3))+1 << ".\t";
}
else {};
if (byteData[i] >= 200 && byteData[i + 1] >= 200 && byteData[i + 2] >= 200)
cout << " ";
else
cout << "#";
}
getchar();
return 0;
}
unsigned char* readBMP(char* filename)
{
int i;
FILE* f = fopen(filename, "rb");
unsigned char info[54];
fread(info, sizeof(unsigned char), 54, f); // read the 54-byte header
// extract image height and width from header
int width = *(int*)&info[18];
int height = *(int*)&info[22];
int size = -3 * width * height;
unsigned char* data = new unsigned char[size]; // allocate 3 bytes per pixel
fread(data, sizeof(unsigned char), size, f); // read the rest of the data at once
fclose(f);
//BGR -> RGB
for (i = 0; i < size; i += 3)
{
unsigned char tmp = data[i];
data[i] = data[i + 2];
data[i + 2] = tmp;
}
return data;
}